【问题标题】:How to merge a list of data.tables without getting splitted columns?如何在不拆分列的情况下合并 data.tables 列表?
【发布时间】:2019-04-25 15:05:31
【问题描述】:

我即将合并大型数据集。这就是我试用 data.table 并对其速度感到兴奋的原因。

# base R
system.time(
  M1 <- Reduce(function(...) merge(..., all=TRUE), L)
  )
# user  system elapsed 
# 5.05    0.00    5.20 

# data.table    
library(data.table)
L.dt <- lapply(L, function(x) setkeyv(data.table(x), c("sid", "id")))
system.time(
  M2 <- Reduce(function(...) merge(..., all=TRUE), L.dt)
  )
# user  system elapsed 
# 0.12    0.00    0.12

两种方法产生相同的值,但是有些列是用 data.table 分割的。

基础 R:

set.seed(1)
car::some(M1, 5)
#        sid    id         V3        V4          a         b
# 60504    1 60504 -0.6964804 -1.210195         NA        NA
# 79653    1 79653 -2.5287163 -1.087546         NA        NA
# 111637   2 11637  0.7104236        NA -1.7377657        NA
# 171855   2 71855  0.2023342        NA -0.6334279        NA
# 272460   3 72460 -0.5098994        NA         NA 0.2738896

data.table:

set.seed(1)
car::some(M2, 5)
#    sid    id       V3.x        V4      V3.y          a         V3         b
# 1:   1 60504 -0.6964804 -1.210195        NA         NA         NA        NA
# 2:   1 79653 -2.5287163 -1.087546        NA         NA         NA        NA
# 3:   2 11637         NA        NA 0.7104236 -1.7377657         NA        NA
# 4:   2 71855         NA        NA 0.2023342 -0.6334279         NA        NA
# 5:   3 72460         NA        NA        NA         NA -0.5098994 0.2738896

我错过了什么吗?还是有一种简单的方法可以解决这个问题,即合并拆分列? (我不想使用任何其他包。)

数据

fun <- function(x){
  set.seed(x)
  data.frame(cbind(sid=x, id=1:1e5, matrix(rnorm(1e5*2), 1e5)))
}
tmp <- lapply(1:3, fun)
df1 <- tmp[[1]]
df2 <- tmp[[2]]
df3 <- tmp[[3]]
rm(tmp)
names(df2)[4] <- c("a")
names(df3)[4] <- c("b")
L <- list(df1, df2, df3)

相关: 1, 2

【问题讨论】:

    标签: r merge data.table


    【解决方案1】:

    base::merge 中的by 参数默认为intersect(names(x), names(y)),其中xy 是要合并的两个表。因此,base::merge 也使用V3 作为合并键。

    data.table::merge 中的by 参数默认为两个表之间的共享键列(即在这种情况下为sidid)。由于这些表有名为 V3 的列,因此后缀会附加到新列中。

    因此,如果您的意图是按所有公共列合并,您可以识别公共列,设置键然后合并:

    commcols <- Reduce(intersect, lapply(L, names))
    L.dt <- lapply(L, function(x) setkeyv(data.table(x), commcols))
    M2 <- Reduce(function(...) merge(..., all=TRUE), L.dt)
    

    【讨论】:

    • 好吧,在我的真实数据中,你可以想象,V3s 有数百个,这才是重点。
    • 如果你真的想通过 V3 合并,你可以指定你的 by 列。或L.dt &lt;- lapply(L, function(x) setkeyv(data.table(x), c("sid", "id", "V3"))),如果这确实是您的意图以及您对base::merge所做的事情@
    • 然后继续将as 和bs 和cs 和...从dts 合并。
    • 只需使用by=Reduce(intersect, lapply(L.dt, names))识别常用列
    • 不过,我有一个关于真实数据的后续问题。错误消息x has some duplicated column name(s) 引用 118 个名称,数据有 431 个名称。认为它与intersect 有关并尝试union 但没有帮助。你能在这里澄清一下吗,还是我应该问另一个问题?
    猜你喜欢
    • 2011-07-14
    • 1970-01-01
    • 2018-06-21
    • 1970-01-01
    • 2021-03-22
    • 2020-03-21
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    相关资源
    最近更新 更多