R - 将列表转换为DataFrame

时间:2015-02-15 14:02:56

标签: r list dataframe apply

有一个这样的列表,从1开始。

[[7158]]
[1] 81 72

[[7159]]
[1] 81 69

[[7160]]
[1] 81 79

[[7161]]
[1] 81 84

这需要更改为数据框,其中每个元素中的第一个数字在一个数据框列中对齐,每个元素中的第二个数字放在数据框的第二列中。所以它应该像这样结束

> data.frame("col1" = c(81, 81, 81, 81), "col2" = c(72, 69, 79, 84))
  col1 col2
1   81   72
2   81   69
3   81   79
4   81   84

我尝试过do.call(rbind.data.frame, my_list),但它似乎将数字放在大量的列中,而不是将其强制转换为所需的两列。使用循环执行此操作将非常简单,但R方式是什么?感谢。

5 个答案:

答案 0 :(得分:8)

只需设置名称:

mylist <- list(c(81,72), c(81,63), c(81,79))
setNames(do.call(rbind.data.frame, mylist), c("col1", "col2"))
#  col1 col2
#1   81   72
#2   81   63
#3   81   79

与其他一些解决方案相比,这也适用于混合数据类型:

mylist <- list(list("a", 72), list("b", 63), list("c", 79))
res <- setNames(do.call(rbind.data.frame, mylist), c("col1", "col2"))
str(res)
#'data.frame':  3 obs. of  2 variables:
# $ col1: Factor w/ 3 levels "a","b","c": 1 2 3
# $ col2: num  72 63 79

答案 1 :(得分:4)

您可以尝试以下任何一项:

do.call(rbind, my_list)

t(simplify2array(my_list))

library(stringi)
stri_list2matrix(my_list, byrow = TRUE)

以上所有内容都会生成两列matrix,其中包含您描述的数据,因此您可以使用as.data.frame获取data.frame

上述替代方案的时间安排以及@Roland的建议can be found at this Gist。总结一下,&#34; stringi&#34;方法将是迄今为止提出的最快的选择。如果我没有弄错,{&1;}在&#34; data.table&#34;也应该支持转换向量列表 - 但我没有在GitHub上用开发版本进行测试来验证,所以我没有在这里包含该选项。

答案 2 :(得分:1)

您可以尝试使用

Reduce( rbind, lapply(t1, t) )

答案 3 :(得分:1)

另一个想法:

mylist = list(c(81, 72), c(81, 69), c(81, 79), c(81, 84))

f4 = function(x) 
{
    tlist = lapply(seq_along(x[[1]]), 
                   function(i) unlist(lapply(x, "[[", i)))
    structure(tlist, class = "data.frame", 
              row.names = .set_row_names(as.integer(length(tlist[[1]]))), 
              names = paste("col", seq_along(tlist), sep = ""))
}

f4(mylist)
#  col1 col2
#1   81   72
#2   81   69
#3   81   79
#4   81   84

与其他选项的基准:

library(stringi)              
f1 = function(x)
  setNames(as.data.frame(type.convert(stri_list2matrix(x, byrow = TRUE))), 
           paste("col", seq_along(x[[1]]), sep = ""))

f2 = function(x)
  setNames(do.call(rbind.data.frame, x), 
           paste("col", seq_along(x[[1]]), sep = ""))

f3 = function(x)
  setNames(as.data.frame(Reduce(rbind, lapply(x, t))), 
           paste("col", seq_along(x[[1]]), sep = "")) 

myls = replicate(1e3, sample(1e2), simplify = F)
identical(f1(myls), f2(myls))
#[1] TRUE
identical(f1(myls), f3(myls))
#[1] TRUE
identical(f1(myls), f4(myls))
#[1] TRUE
microbenchmark::microbenchmark(f1(myls), f2(myls), f3(myls), f4(myls), times = 10)
#Unit: milliseconds
#     expr       min        lq    median        uq       max neval
# f1(myls)  57.66834  58.46979  59.39131  61.43861 102.27333    10
# f2(myls) 393.81459 404.29019 418.03128 422.87740 494.79857    10
# f3(myls) 288.39078 299.51680 305.21727 314.75482 374.48683    10
# f4(myls)  52.54991  53.26575  55.34472  59.25559  75.19658    10

答案 4 :(得分:1)

current development version of data.table, v1.9.5中,有一个新功能transpose(),用于转置列表。我们可以将其与setDT()一起使用,如下所示。

require(data.table) # v1.9.5+
ll = lapply(1:1e6, function(x) sample(100, 2))
dt = setDT(transpose(ll))

system.time(setDT(transpose(ll))
#    user  system elapsed 
#   0.073   0.000   0.073 

如果你想要一个data.frame,那么你可以在这个结果上使用setDF()(它将data.table转换为data.frame而不需要任何副本)。