【问题标题】:Joining and grouping two data tables连接和分组两个数据表
【发布时间】:2013-04-05 09:33:16
【问题描述】:

假设我有以下两个数据表:

dt1 <- data.table(id=1:3,val1=c("a","a","b"),key="id")
#    id val1
# 1:  1    a
# 2:  2    a
# 3:  3    b


dt2 <- data.table(id=c(1:3,1:2),val2=10:14,key="id")
#    id val2
# 1:  1   10
# 2:  1   13
# 3:  2   11
# 4:  2   14
# 5:  3   12

假设dt1 是由他们的id 识别的人员列表,dt2 是对这些人的观察列表,通讯员id

现在,我想计算每组val1val2 的平均值。我知道我可以通过以下方式做到这一点:

dt1[dt2][,mean(val2),by=val1]
#    val1 V1
# 1:    a 12
# 2:    b 12

但我也在常见问题解答(第 1.14 节)中读到它效率不高(至少对于非常大的数据表)。

那么,有没有更好、更有效的方法呢?

编辑:另一个相关问题:我刚刚看到以下两行将给出相同的结果:

dt1[dt2][,mean(val2),by=val1]
dt2[dt1][,mean(val2),by=val1]

它们是等价的还是两者之间有区别?

【问题讨论】:

  • 我怀疑 reshape 包可能会有所帮助(尽管我还没有为您提供详细的解决方案)。将两个数据集转换为长格式,将它们连接在一起,然后再转换回来。

标签: r data.table


【解决方案1】:

在您的情况下,可以这样做。 iiuc 文档解释的内容例如在这种情况下(您没有对所有列进行分组/聚合):

dt1 <- data.table(id=1:3,val1=c("a","a","b"),key="id")
dt2 <- data.table(id=c(1:3,1:2),val2=10:14,key="id")

dt2[, val3 := rep(5:7, c(2,1,2))]
#    id val2 val3
# 1:  1   10    5
# 2:  1   13    5
# 3:  2   11    6
# 4:  2   14    7
# 5:  3   12    7

现在,假设您想为每个 val1 单独获取 val2 的平均值,那么连接所有列是没有意义的。在这种情况下,您可以这样做:

dt1[dt2, list(val1, val2)][, mean(val2), by=val1]
#    val1 V1
# 1:    a 12
# 2:    b 12

而不是做:

# gives same result but performs join on all columns
dt1[dt2][, mean(val2), by=val1]

对于第二个问题,我想了解dt1[dt2]dt2[dt1] 的区别很重要。为此,您的数据并不是最好的例子。假设,

dt1 <- data.table(id=c(1,4,5), val1=c("a","a","b"))
dt2 <- data.table(id=c(1,2,3,6,7,8), val2=c(6,5,3,4,2,1))

setkey(dt1, "id")
setkey(dt2, "id")

dt1[dt2]dt2 中的每个id 进行取值,并获取dt1 中所有其他列的对应值以执行连接:

dt1[dt2]
#    id val1 val2
# 1:  1    a    6
# 2:  2   NA    5
# 3:  3   NA    3
# 4:  6   NA    4
# 5:  7   NA    2
# 6:  8   NA    1

dt2[dt1]dt1 中的每个id 取来自dt2 其他列的相应值来执行连接:

dt2[dt1]
#    id val2 val1
# 1:  1    6    a
# 2:  4   NA    a
# 3:  5   NA    b

请注意,dt1[dt2] 中的值包含dt2 的 id。同样dt2[dt1] 仅包含dt1 中的那些。在您的情况下,由于ids 完全相同(忽略它们发生的次数),因此两个连接都会为您提供相同的连接(除了列的顺序),iiuc。


只是为了使这部分完整,如果您想要“完整”连接,请使用 mergeall=TRUE。实现了merge.data.table方法。

merge(dt1, dt2, all = TRUE)

merge(dt1, dt2, all.x = TRUE) 
# is equivalent to
dt2[dt1]

merge(dt1, dt2, all.y = TRUE)
# is equivalent to
dt1[dt2]

【讨论】:

  • 感谢您的回答,我知道您将是第一个 :) 我刚刚在我的问题文本中添加了第二个相关问题,如果您有时间花在上面...
  • 这很清楚,我希望我可以给你几票...感谢您抽出宝贵时间回答得如此清楚。现在我只需要了解.N 在这两种情况下的不同值。但这是另一个问题:)
  • 前面对问题2答案的解释有错误,也许你应该再看一遍。对此感到抱歉。
猜你喜欢
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-31
  • 2014-02-15
  • 2021-12-07
相关资源
最近更新 更多