【问题标题】:Binding list of data.tables by columns, and by reference按列和引用绑定 data.tables 列表
【发布时间】:2018-01-19 03:03:50
【问题描述】:

假设我有以下列表:

X = list(data.table(1:2,3:4,5:6), 
         data.table(letters[1:2], letters[3:4]))

我想将列表中的元素按列绑定到单个 data.table 中。 输出将与生成的相同

do.call(cbind, X)

但是,由于我的原始列表和包含的数据表非常大,如果我可以通过引用来执行此操作会更好,而不是使用 cbind() 复制整个对象。有没有办法做到这一点?类似于 rbindlist() 的东西相当于按列绑定,我看到这被标记为待办事项......

抱歉,如果这个简单的问题已经在其他地方得到解答,而我错过了答案。

【问题讨论】:

标签: r data.table


【解决方案1】:

下面的呢?

# check.names = TRUE forces unique names on the output
setDT(
  unlist(X, recursive = FALSE),
  check.names = TRUE
)[]
#    V1 V2 V3 V4 V5
# 1:  1  3  5  a  c
# 2:  2  4  6  b  d

【讨论】:

  • 让我检查一下大数据集
  • 在我的数据集上,所有三个解决方案的表现都相似,但是,我喜欢这个,因为它最简洁。感谢您提供有用的建议。
【解决方案2】:

来自dplyrbind_colsdo.call(cbind 相比似乎更有效,它返回一个data.table

library(dplyr)
bind_cols(X)
#   V1 V2 V3 V11 V21
#1:  1  3  5   a   c
#2:  2  4  6   b   d

基准测试

set.seed(24)
X1 <- lapply(1:10, function(i)
      as.data.table(matrix(sample(1:9, 1e5*1e3, replace = TRUE), nrow = 1e5, ncol = 1e3)))

system.time({
   bind_cols(X1)
  })
#user  system elapsed 
#   0.01    0.00    0.02 

system.time({
    do.call(cbind, X1)
   })
#user  system elapsed 
#   2.22   37.84   40.93 

system.time({
  setDT(unlist(X1, recursive = FALSE), check.names = TRUE)
  })
#  user  system elapsed 
#   0.05    0.00    0.05 

check.names = FALSE

system.time({
   setDT(unlist(X1, recursive = FALSE), check.names = FALSE)
  })
#  user  system elapsed 
#  0.01    0.00    0.02 

同样基于@MichaelChirico的示例数据进行测试

set.seed(24)
NN <- 1e6
L <- lapply(integer(20L), function(ii) {
    setDT(lapply(integer(sample(15L, 1L)), function(x) rnorm(NN))) }) 

system.time({
   bind_cols(L)
  })
# user  system elapsed 
#      0       0       0 

system.time({
    do.call(cbind, L)
   })
# user  system elapsed 
#   0.44    0.53    0.97 


system.time({
base = L[[1L]]
jj = ncol(base) + 1L
for (ii in 2L:length(L)) {
  for (col_j in seq_len(ncol(L[[ii]]))) {
    set(base, , sprintf('V%d', jj), L[[ii]][[col_j]])
    jj = jj + 1L
  }
}
 })
#user  system elapsed 
#  0.12    0.33    0.46 

以及@MichaelChirico 的更新方法

system.time({
   setDT(unlist(L, recursive = FALSE), check.names = TRUE)
   })
#  user  system elapsed 
#     0       0       0 

【讨论】:

  • @MichaelChirico 在第二个数据集中,它给出了相似的时间,即 0,而在第一个数据集中,它给出了 0.05
  • 看来check.names for setDTtibble::repair_names 慢——如果check.names = FALSE setDT 快得多,否则bind_cols 是;无论如何,即使对于庞大的数据集,它们也具有竞争力,而且bind_cols 语法肯定更干净;如果您愿意加载其他库,我更喜欢dplyr 解决方案这里
  • 你是对的。它的性能与bind_cols 相似
猜你喜欢
  • 2012-02-21
  • 1970-01-01
  • 2012-08-28
  • 2015-09-07
  • 2020-11-21
  • 1970-01-01
  • 1970-01-01
  • 2019-02-13
  • 1970-01-01
相关资源
最近更新 更多