2010-11-10 62 views
5

我希望深入瞭解爲何發生這種情況,以及我如何更有說服力地做到這一點。爲什麼sapply返回需要轉置的矩陣,然後轉置的矩陣不會附加到數據幀?

當我使用sapply時,我希望它返回一個3x2矩陣,但它返回一個2x3矩陣。爲什麼是這樣?爲什麼將它附加到另一個數據框很困難?

a <- data.frame(id=c('a','b','c'), var1 = c(1,2,3), var2 = c(3,2,1)) 
out <- sapply(a$id, function(x) out = a[x, c('var1', 'var2')]) 
#out is 3x2, but I would like it to be 2x3 
#I then want to append t(out) (out as a 2x3 matrix) to b, a 1x3 dataframe 
b <- data.frame(var3=c(0,0,0)) 

,當我嘗試將這些,

b[,c('col2','col3')] <- t(out) 

,我得到的錯誤是:

Warning message: 
In `[<-.data.frame`(`*tmp*`, , c("col2", "col3"), value = list(1, : 
    provided 6 variables to replace 2 variables 

雖然下面似乎得到期望的結果:

rownames(out) <- c('col1', 'col2') 
b <- cbind(b, t(out)) 

我無法操作Ë變量:

b$var1/b$var2 

回報

Error in b$var1/b$var2 : non-numeric argument to binary operator 

謝謝!

+1

什麼是你想用這個數據做什麼?你的例子並沒有做任何有意義的事情。 – hadley 2010-11-10 03:20:36

+2

@hadley:該示例遵循R發佈準則,提供一個最小的可行示例。實際情況相當複雜,複雜性會削弱核心問題。我使用泰勒級數展開函數估計了20個不同參數的模型靈敏度,並接受了20x8數據幀作爲輸入。如果您願意,我很樂意發送完整的可重複使用的示例,但尚未準備好公開。 – 2010-11-10 04:19:38

+1

你需要在容易理解的東西和捕捉你正在努力解決的問題的本質之間尋找一個快樂的媒介。在你現在的例子中,似乎你想讓'b'等於'a'。 – hadley 2010-11-10 13:50:24

回答

3

要擴大迪文的答案:這將有助於看看你的out對象的結構。它解釋了爲什麼b$var1/b$var2不符合你的期望。

> out <- sapply(a$id, function(x) out = a[x, c('var1', 'var2')]) 
> str(out) # this isn't a data.frame or a matrix... 
List of 6 
$ : num 1 
$ : num 3 
$ : num 2 
$ : num 2 
$ : num 3 
$ : num 1 
- attr(*, "dim")= int [1:2] 2 3 
- attr(*, "dimnames")=List of 2 
    ..$ : chr [1:2] "var1" "var2" 
    ..$ : NULL 

apply家庭的功能被設計爲在向量和陣列的工作,所以你需要照顧與data.frames(通常是向量的列表)時使用它們。您可以使用這樣的事實,即使用lapply,data.frames是您的優勢列表。

> out <- lapply(a$id, function(x) a[x, c('var1', 'var2')]) # list of data.frames 
> out <- do.call(rbind, out) # data.frame 
> b <- cbind(b,out) 
> str(b) 
'data.frame': 3 obs. of 4 variables: 
$ var3: num 0 0 0 
$ var1: num 1 2 3 
$ var2: num 3 2 1 
$ var3: num 0 0 0 
> b$var1/b$var2 
[1] 0.3333333 1.0000000 3.0000000 
2

首先有一點R符號。如果你看看sapply的代碼,你會發現你的問題的答案。 sapply函數檢查列表長度是否全部相等,如果是,則首先「unlist()」它們,然後將該系列列表作爲array()的數據參數。由於數組(如矩陣())默認按列主要順序排列其值,這就是你所得到的。名單變成了他們的一面。如果你不喜歡它,那麼你可以定義一個新的功能tsapply將返回轉置值:

> tsapply <- function(...) t(sapply(...)) 
> out <- tsapply(a$id, function(x) out = a[x, c('var1', 'var2')]) 
> out 
    var1 var2 
[1,] 1 3 
[2,] 2 2 
[3,] 3 1 

...一個3×2矩陣。

+1

從技術上講,「out」不是矩陣。這是一個包含dim和dimnames屬性的列表。例如。 'out%*%t(out)'失敗。 – 2010-11-10 03:17:34

+0

R除外認爲它是一個矩陣:> is.matrix(out) [1] TRUE – 2010-11-11 17:37:29

1

看一看ddply從plyr包

a <- data.frame(id=c('a','b','c'), var1 = c(1,2,3), var2 = c(3,2,1)) 

library(plyr) 
ddply(a, "id", function(x){ 
    out <- cbind(O1 = rnorm(nrow(x), x$var1), O2 = runif(nrow(x))) 
    out 
})