2010-11-10 61 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 
})