Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 如何将列表列表转换为数据帧-不相同列表_R - Fatal编程技术网

R 如何将列表列表转换为数据帧-不相同列表

R 如何将列表列表转换为数据帧-不相同列表,r,R,我有一个列表,其中每个元素都是一个命名列表,但每个元素都不相同。我读过关于如何将列表列表转换为数据帧和数据帧的解决方案,但当列表不相同时,所有这些都不起作用 示例-注意,我也有混合类型,如果解决方案将所有内容强制为character,这是很好的 lisnotOK <- list(list(a=1, b=2, c="hi"), list(b=2, c="hello", d="nope")) 任何使用rbind,或试图将lisnotOK放入矩阵的解决方案都将失败,而上面链接的帖子中的任何示例

我有一个列表,其中每个元素都是一个命名列表,但每个元素都不相同。我读过关于如何将列表列表转换为数据帧和数据帧的解决方案,但当列表不相同时,所有这些都不起作用

示例-注意,我也有混合类型,如果解决方案将所有内容强制为character,这是很好的

lisnotOK <- list(list(a=1, b=2, c="hi"), list(b=2, c="hello", d="nope"))
任何使用
rbind
,或试图将
lisnotOK
放入矩阵的解决方案都将失败,而上面链接的帖子中的任何示例都不起作用,即使我尝试使用
rbind\u all
rbind.fill

一种解决方案是丑陋的for循环,其中每个连续列表都更改为一个数据帧,并使用
rbind\u all
绑定到一个数据帧


有人知道一个有效的解决方案吗?

使用
lappy
将列表元素转换为
数据。frame
s和
rbind\u all

rbind_all(lapply(lisnotOK,data.frame))
   a b     c    d
1  1 2    hi <NA>
2 NA 2 hello nope
Warning message:
In rbind_all(lapply(lisnotOK, data.frame)) :
  Unequal factor levels: coercing to character

考虑到生成的矩阵都是相同类型(例如,
字符
),您可以尝试编写自己的函数,如下所示:

list2mat <- function(inList) {
  UL <- unlist(inList)
  Nam <- unique(names(UL))
  M <- matrix(NA_character_, 
              nrow = length(inList), ncol = length(Nam), 
              dimnames = list(NULL, Nam))
  Row <- rep(seq_along(inList), sapply(inList, length))
  Col <- match(names(UL), Nam)
  M[cbind(Row, Col)] <- UL
  M
}
这应该很快,因为所有内容都是预先分配的,并且您正在使用矩阵索引


更新:基准(因为你说效率是个问题)
fun1任何在绑定前对列表的每个元素使用
data.frame(.)
的函数都会非常低效(更不用说没有必要了)。下面是另一种使用
data.table
rbindlist
(来自v1.9.3)的方法,您可以从中获得

它适用于列表列表(如本问题中)、data.frames和data.tables

如果不是这样,那么我就使用Ananda的
list2mat
函数(如果您的类型都相同的话)


Ananda的
L2
数据基准:

fun1 <- function(inList) ldply(inList, as.data.frame)
fun2 <- function(inList) list2mat(inList)
fun3 <- function(inList) rbindlist(inList, fill=TRUE)
fun4 <- function(inList) rbind_all(lapply(inList, as.data.frame))

microbenchmark(fun1(L2), fun2(L2), fun3(L2), fun4(L2), times = 10)
# Unit: milliseconds
#      expr         min          lq      median          uq         max neval
#  fun1(L2) 1927.857847 2161.432665 2221.999940 2276.241366 2366.649614    10
#  fun2(L2)   12.039652   12.167613   12.361629   12.483751   16.040885    10
#  fun3(L2)    1.225929    1.374395    1.473621    1.510876    1.858597    10
#  fun4(L2) 1435.153576 1457.053482 1492.334965 1548.547706 1630.443430    10

fun1这很好,不幸的是我发现它在我的实际列表中不起作用,因为有些元素包含NULL。但这很容易在另一圈中修复。@akrun,为什么?
ldply
有什么特别之处?@akrun,这是因为您没有查看
ldply
的代码。按照这种逻辑,我的代码就是
list2mat(lisnotOK)
:-)+1。这是一个巨大的差异。不确定这是否适用于'rbindlist(,fill=TRUE)。我没有data.table的新版本要测试。感谢更新的基准测试。我没有意识到,
rbindlist
是这样工作的——或者是1.9.3中的一个更新(因此您指定了版本号)?@AnandaMahto,
rbind
从1.9.2开始就有
fill=TRUE
,但它是在R中实现的。在1.9.3中,所有内容都被移到了C,并且
rbist
被修饰。您可以阅读更多。rbindlist中的
fill=TRUE
参数万岁!
list2mat <- function(inList) {
  UL <- unlist(inList)
  Nam <- unique(names(UL))
  M <- matrix(NA_character_, 
              nrow = length(inList), ncol = length(Nam), 
              dimnames = list(NULL, Nam))
  Row <- rep(seq_along(inList), sapply(inList, length))
  Col <- match(names(UL), Nam)
  M[cbind(Row, Col)] <- UL
  M
}
list2mat(lisnotOK)
#      a   b   c       d     
# [1,] "1" "2" "hi"    NA    
# [2,] NA  "2" "hello" "nope"
fun1 <- function(inList) ldply(inList, data.frame)
fun2 <- function(inList) list2mat(inList)

library(microbenchmark)
microbenchmark(fun1(lisnotOK), fun2(lisnotOK))
# Unit: microseconds
#            expr      min        lq    median       uq      max neval
#  fun1(lisnotOK) 4193.808 4340.0585 4523.3000 4912.233 7600.341   100
#  fun2(lisnotOK)  163.784  182.3865  211.2515  236.910  363.489   100

L2 <- unlist(replicate(1000, lisnotOK, simplify=FALSE), recursive=FALSE)
microbenchmark(fun1(L2), fun2(L2), times = 10)
# Unit: milliseconds
#      expr        min         lq     median         uq        max neval
#  fun1(L2) 3032.71572 3106.79006 3196.17178 3306.11756 3609.67445    10
#  fun2(L2)   24.16817   24.86991   25.65569   27.44128   29.41908    10
require(data.table) ## 1.9.3
rbindlist(lisnotOK, fill=TRUE)
#     a b     c    d
# 1:  1 2    hi   NA
# 2: NA 2 hello nope
fun1 <- function(inList) ldply(inList, as.data.frame)
fun2 <- function(inList) list2mat(inList)
fun3 <- function(inList) rbindlist(inList, fill=TRUE)
fun4 <- function(inList) rbind_all(lapply(inList, as.data.frame))

microbenchmark(fun1(L2), fun2(L2), fun3(L2), fun4(L2), times = 10)
# Unit: milliseconds
#      expr         min          lq      median          uq         max neval
#  fun1(L2) 1927.857847 2161.432665 2221.999940 2276.241366 2366.649614    10
#  fun2(L2)   12.039652   12.167613   12.361629   12.483751   16.040885    10
#  fun3(L2)    1.225929    1.374395    1.473621    1.510876    1.858597    10
#  fun4(L2) 1435.153576 1457.053482 1492.334965 1548.547706 1630.443430    10