将数据框中的每一行转换为列表项

19

我有一些关于数据框处理的操作,希望使用 mclapply() 或其他类似的 lapply() 函数加速。对我来说,最简单的方法之一是将数据框的每一行作为列表中的一个小数据框。我可以使用 plyr 很容易地实现这一点:

df <- data.frame( a=rnorm(1e4), b=rnorm(1e4))
require(plyr)
system.time(myList <- alply( df, 1, function(x) data.frame(x) ))

一旦我的数据被转换成列表,我就可以轻松地执行以下操作:

mclapply( myList, function(x) doSomething(x$a) )

这个方法效果很好,但是我的数据量非常大,adply() 步骤非常慢。我尝试在 adply 步骤上使用多核并行后端,但即使我注册了 8 个处理器,它也从未使用过一个以上的处理器。我怀疑并行选项可能无法处理这种类型的问题。

有什么建议可以让这个过程更快吗?也许用基本的 R 解决办法?


4
为什么不使用alply(df, 1, function(x) doSomething(x), .parallel = TRUE) - hadley
2个回答

17

只需使用 split。它比您的 adply 行快几倍。

> system.time(myList <- alply( df, 1, function(x) data.frame(x) ))
   user  system elapsed 
   7.53    0.00    7.57 
> system.time( splitList <- split(df, 1:NROW(df)) )
   user  system elapsed 
   1.73    0.00    1.74 
> 

我怀疑adply的并行后端仅用于函数评估(而不是分割和重新组合)。

更新:
如果您可以将您的数据框转换为矩阵,则下面的解决方案将非常快速。 您可能可以使用split,但它会放弃名称并在每个列表元素中返回一个向量。

> m <- as.matrix(df)
> system.time( matrixList <- lapply(1:NROW(m), function(i) m[i,,drop=FALSE]) )
   user  system elapsed 
   0.02    0.00    0.02
> str(matrixList[[1]])
 num [1, 1:2] -0.0956 -1.5887
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:2] "a" "b"
> system.time( matrixSplitList <- split(m, 1:NROW(m)) )
   user  system elapsed 
   0.01    0.00    0.02 
> str(matrixSplitList[[1]])
 num [1:2] -0.0956 -1.5887

我认为你对于分割和合并的结论是正确的。 - JD Long
今天我学到的教训是,“矩阵上的所有操作都更快”。 - JD Long
更公平的比较是 system.time(myList <- alply( df, 1, identity )),但仍然太慢了 :( - hadley
如果R有一个快速的函数可以通过任意数量的维度对对象进行下标,那么它应该可以像split一样快。 - hadley

6
这个怎么样?
jdList <- split(df, 1:nrow(df))

> class(jdList[[1]])
[1] "data.frame"

> system.time(jdList <- split(df, 1:nrow(df)))
   user  system elapsed 
   1.67    0.02    1.70 
> system.time(myList <- alply( df, 1, function(x) data.frame(x) ))
   user  system elapsed 
    7.2     0.0     7.3 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接