【问题标题】:Unroll R data.frame list column retaining the other values in the row [duplicate]展开 R data.frame 列表列,保留行中的其他值[重复]
【发布时间】:2015-07-22 00:23:17
【问题描述】:

我需要有效地“展开” R data.frame 中的列表列。例如,如果我有一个 data.frame 定义为:

dbt <- data.frame(values=c(1,1,1,1,2,3,4), 
                  parm1=c("A","B","C","A","B","C","B"),
                  parm2=c("d","d","a","b","c","a","a"))

然后,假设分析生成一列作为列表,类似于以下输出:

agg <- aggregate(values ~ parm1 + parm2, data=dbt, 
                 FUN=function(x) {return(list(x))})

聚合后的 data.frame 看起来像(其中 class(agg$values) == "list"):

  parm1 parm2 values
1     B     a      4
2     C     a   1, 3
3     A     b      1
4     B     c      2
5     A     d      1
6     B     d      1

我想展开“值”列,在所有 data.frame 行中以有效的方式为列表的每个元素重复 parm1 和 2 值(添加更多行)。

在顶层,我编写了一个函数,该函数在应用中调用的 for 循环中进行展开。 真的效率低下,(聚合的 data.frame 大约需要一个小时来创建,近 24 小时来展开,完全展开的数据有大约 50 万条记录)。我正在使用的顶层是:

unrolled.data <- do.call(rbind, apply(agg, 1, FUN=unroll.data))

该函数只是在值列对象上调用 unlist() 然后在 for 循环中构建一个 data.frame 对象作为返回对象。

环境有些受限,我无法使用 tidyr、data.table 和 splitstackshape 库,它不仅需要是 base:: 中的函数,而且仅限于 v3.1.1 及之前版本中可用的函数。因此this (not really a duplicate) question 中的答案不适用。

有什么更快的建议吗?

谢谢!

【问题讨论】:

  • 谢谢,但在这种情况下 tidyr 库不可用。其他想法?
  • 不幸的是 splitstackshape 或 data.table 也不是(感谢参考问题,我没有看到它)。

标签: r list dataframe


【解决方案1】:

使用base R,你可以试试

with(agg, {
    data.frame(
        lapply(agg[,1:2], rep, times=lengths(values)),
        values=unlist(values)
    )
})
#      parm1 parm2 values
# 1.2      B     a      4
# 1.31     C     a      1
# 1.32     C     a      3
# 2.1      A     b      1
# 3.2      B     c      2
# 4.1      A     d      1
# 4.2      B     d      1

替代方案的时间安排(感谢@thelatemail)

library(dplyr)
agg %>%
  sample_n(1e7, replace=T) -> bigger

system.time(
    with(bigger, { data.frame(lapply(bigger[,1:2], rep, times=lengths(values)), values=unlist(values)) })
)
# user  system elapsed 
# 3.78    0.14    3.93 

system.time(
    with(bigger, { data.frame(bigger[rep(rownames(bigger), lengths(values)), 1:2], values=unlist(values)) })
)
# user  system elapsed 
# 11.30    0.34   11.64 

【讨论】:

  • 您可以将中间的 lapply 位替换为行索引调用 - agg[rep(rownames(agg),lengths(values)),1:2] ,这样应该会更快。
  • @thelatemail 不知道为什么,但它实际上似乎有点慢。会不会多次应用[函数?
  • 不应该,[ 调用应该只发生一次,rep 调用也应该如此。也许子集只是比对每一列的多次调用慢。我觉得很奇怪。
  • 当然,如果lapply 循环的变量多于 2 个,[ 的开销会相应减少。对于这个例子,你原来的可能是最好的。
  • @TimH lengths 在 R-3.2+ 中引入,旧的方式是 sapply(values, length)
猜你喜欢
  • 2021-06-25
  • 1970-01-01
  • 2020-03-17
  • 2019-01-18
  • 2015-10-10
  • 1970-01-01
  • 2021-02-23
  • 1970-01-01
  • 2022-10-13
相关资源
最近更新 更多