【问题标题】:Why does sapply return a matrix that I need to transpose, and then the transposed matrix will not attach to a dataframe?为什么 sapply 返回一个我需要转置的矩阵,然后转置的矩阵不会附加到数据帧?
【发布时间】:2011-05-07 14:58:20
【问题描述】:

我希望能深入了解为什么会发生这种情况,以及如何才能更有说服力地做到这一点。

当我使用 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

谢谢!

【问题讨论】:

  • 你想用这些数据做什么?你的例子并没有真正做任何有意义的事情。
  • @hadley:该示例遵循 R 发布指南,提供了一个最小的、可行的示例。实际情况相当复杂,复杂性会偏离中心问题。我的函数使用泰勒级数展开估计模型对 20 个不同参数的敏感性,并接受 20x8 数据帧作为输入。如果您愿意,我很乐意发送一个完整的可重现示例,尽管它尚未准备好公开。
  • 您需要在易于理解的事物和抓住您正在努力解决的问题的本质之间寻求一种快乐的媒介。在您当前的示例中,您似乎正在尝试使 b 等于 a。
  • @hadley:谢谢你的提示,我会记住的。

标签: r data-structures vectorization apply


【解决方案1】:

扩展 DWin 的答案:查看 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()。由于array(如 matrix() )默认按列主要顺序排列其值,这就是你得到的。名单变得对他们有利。如果您不喜欢它,那么您可以定义一个新函数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 x 2 矩阵。

    【讨论】:

    • 从技术上讲,out 不是矩阵。这是一个带有dim 和dimnames 属性的列表。例如。 out %*% t(out) 失败。
    • 除了 R 认为它是一个矩阵:> is.matrix(out) [1] TRUE
    【解决方案3】:

    看看 plyr 包中的 ddply

    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
    })
    

    【讨论】:

      猜你喜欢
      • 2012-10-28
      • 2012-03-20
      • 2014-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多