2013-02-24 37 views
3

我定義了一個類(tdtfile),它繼承data.frame。我現在試圖定義一個[.data.frame等效替換方法來返回類tdtfile而不是data.frame的適當對象,但遇到問題。自定義類繼承`data.frame`和替換方法

下面是我在做什麼:

# Define Class 
setClass("tdtfile", 
    representation(Comment = "character"), 
    prototype(Comment = NULL), 
    contains = c("data.frame")) 

# Construct instance and populate 
test <- new("tdtfile",Comment="Blabla") 
df <- data.frame(A=seq(26),B=LETTERS) 
for(sName in names(getSlots("data.frame"))){ 
    slot(test,sName) <- slot(df,sName) 
} 

# "Normal" data.frame behavior (loss of slot "Comment") 
str(test[1]) 
# Works as well - will be trying to use that below 
`[.data.frame`(test,1) 

# Try to change replacement method in order to preserve slot structure 
# while accessing data.frame functionality 
setMethod(
    `[`, 
    signature=signature(x="tdtfile"), 
    function(x, ...){ 
    # Save the original 
    storedtdt <- x 
    # Use the fact that x is a subclass to "data.frame" 
    tmpDF <- `[.data.frame`(x, ...) 
    # Reintegrate the results 
    if(inherits(x=tmpDF,what="data.frame")){ 
     for(sName in names(getSlots("data.frame"))){ 
     slot(storedtdt,sName) <- slot(tmpDF,sName) 
     } 
     return(storedtdt) 
    } else { 
     return(tmpDF) 
    } 
    }) 

# Method does not work - data.frame remains complete. WHY? 
str(test[1]) 

# Cleanup 
#removeMethod(
# `[`, 
# signature=signature(x="tdtfile")) 

當調用類似

tdtfile[1] 

這將返回AA tdtfile物體都含有相當data.frame列不僅僅是第一...誰能發現我錯過了什麼?

謝謝你的幫助。

真誠,荷蘭Joh

+0

嗨Joh,歡迎來到SO。你能否詳細說明你的最後一句話。你具體看到什麼,你想看到什麼? – 2013-02-24 08:29:49

+0

感謝您關注此事。我大大改進了這個例子,使其完全獨立/可重複。我正在嘗試做什麼,現在看得清楚(呃)? – balin 2013-02-25 05:40:39

回答

1

你的方法是行爲不當的原因是ij,並drop是您的[方法內自動提供,我相信只是如何在[通用工程的結果。這意味着您需要將這些參數的名稱傳遞給[.data.frame而不是依靠...。不幸的是,這反過來又讓你負責正確處理各種形式的索引。

下面是修改方法定義,做一個體面的工作,雖然它可能不具有完全相同的行爲類似於在該drop爭論的某些用途的純數據幀索引:

setMethod(
    `[`, 
    signature=signature(x="tdtfile"), 
    function(x, ...){ 
     # Save the original 
     storedtdt <- x 
     # Use the fact that x is a subclass to "data.frame" 
     Nargs <- nargs() 
     hasdrop <- "drop" %in% names(sys.call()) 
     if(Nargs==2) { 
      tmpDF <- `[.data.frame`(x, i=TRUE, j=i, ..., drop=FALSE) 
     } else if((Nargs==3 && hasdrop)) { 
      tmpDF <- `[.data.frame`(x, i=TRUE, j=i, ..., drop) 
     } else if(hasdrop) { 
      tmpDF <- `[.data.frame`(x, i, j, ..., drop) 
     } else { 
      tmpDF <- `[.data.frame`(x, i, j, ...) 
     } 
     # Reintegrate the results 
     if (inherits(x=tmpDF, what="data.frame")){ 
      for(sName in names(getSlots("data.frame"))){ 
       slot(storedtdt, sName) <- slot(tmpDF, sName) 
      } 
      return(storedtdt) 
     } else { 
      return(tmpDF) 
     } 
    }) 

與測試的幾個例子object:

> head(test[1]) 
Object of class "tdtfile" 
    A 
1 1 
2 2 
3 3 
4 4 
5 5 
6 6 
Slot "Comment": 
[1] "Blabla" 

> test[1:2,] 
Object of class "tdtfile" 
    A B 
1 1 A 
2 2 B 
Slot "Comment": 
[1] "Blabla" 

我不確定是否有更加規範的方法來做到這一點。也許試圖查看一些S4軟件包的源代碼?

編輯:這是一種類似於上述提取方法的精神置換方法。這個在直接調用[<-之前明確地將對象強制轉換爲數據框,主要是爲了避免在[<-.data.frame的情況下得到的警告。同樣,行爲與純粹的數據框替換方法並不完全相同,儘管可以做更多的工作。

setMethod(
    `[<-`, 
    signature=signature(x="tdtfile"), 
    function(x, ..., value){ 
     # Save the original 
     storedtdt <- x 
     # Use the fact that x is a subclass to "data.frame" 
     Nargs <- nargs() 
     if (any(!names(sys.call()) %in% c("", "i", "j", "value"))) { 
      stop("extra arguments are not allowed") 
     } 
     tmpDF <- data.frame(x) 
     if(Nargs==3) { 
      if (missing(i)) i <- j 
      tmpDF[i] <- value 
     } else if(Nargs==4) { 
      tmpDF[i, j] <- value 
     } 
     # Reintegrate the results 
     for(sName in names(getSlots("data.frame"))){ 
      slot(storedtdt, sName) <- slot(tmpDF, sName) 
     } 
     return(storedtdt) 
    }) 

例子:

> test[2] <- letters 
> test[1,"B"] <- "z" 
> test$A[1:3] <- 99 
> head(test) 
Object of class "tdtfile" 
    A B 
1 99 z 
2 99 b 
3 99 c 
4 4 d 
5 5 e 
6 6 f 
Slot "Comment": 
[1] "Blabla" 

順便說一句,如果它是至關重要的,因爲他們在數據幀做提取/替換工作正是,我會考慮重寫類,以便包含槽數據框,而不是將data.frame作爲超類。繼承構成!

+0

問題文字提到'替換',但代碼完全涉及提取,所以我只是堅持後者。 – regetz 2013-02-25 09:01:20

+0

感謝您的輸入...我將探討這一點,但您的評論似乎表明'測試[1] < - LETTERS'或類似的將仍然不起作用...正如我所說...將經過調查回來... – balin 2013-02-25 12:27:24

+0

@balin:我添加了一個方法,使您的替換示例。 – regetz 2013-02-25 17:57:54