【问题标题】:data.table update join using a constantdata.table 使用常量更新连接
【发布时间】:2017-08-13 17:54:17
【问题描述】:

我想根据联接和固定值更新 data.table 中的行子集。

d1 <- data.table(A = 5:1, B = letters[5:1])    
d2 <- data.table(C = letters[5:1], Z = 6:10)
current.val <- 5

我想要做的是根据与 d2 的连接更新 d1,但仅限于 d1 中 A==5 的位置。像这样:

d1[d2, D := i.Z ,on=.(B==C, A==current.val)]

我目前的方法是向 d2 添加一个新列并将其设置为固定值并在连接中使用它:

d2[, current.val := 5]
d1[d2, D := i.Z ,on=.(B==C, A==current.val)]

这可行,但似乎开销很大。有没有更简单的方法在连接中使用常量值?


(8/14) 基准测试的新比例示例:

d1 <- data.table(A = 100:1, B = 100000000:1, D = as.numeric(NA),  key = c("A", "B"))
d2 <- data.table(C = 100000000:1, Z = c(10:1) / 10, key = "C")
current.val <- 5

system.time(d1[cbind(d2, A = current.val), on = .(B = C, A), D := i.Z])
system.time({setkey(d1, B, A); d1[d1[d2][A == current.val], D := Z]; setkey(d1, A, B)})
system.time(d1[d1[d2][A == current.val], D := Z]) # fastest, if inverse key order is acceptable

【问题讨论】:

  • 您的解决方案看起来很简单。如果您不想创建列,请使用行索引,即i1 &lt;- d1[, .I[A==current.val]]; d1[i1, D:= d1[i1][d2, i.Z[i1], on = .(B==C)]]
  • 不确定您是否在那里进行了正确的基准测试。对于第二个,我收到“vecseq 中的错误 [...] Join results in more than 2^31 rows”。
  • 弗兰克,请参阅下面@gcbenison 的回答 cmets。我会更新帖子以反映工作基准

标签: r performance join data.table


【解决方案1】:

我目前的方法是向 d2 添加一个新列并将其设置为固定值并在连接中使用它[...] 有没有更简单的方法在连接中使用常量值?

这是一个好方法。或者,您可以使用 cbind 在联接中临时添加一列:

d1[cbind(d2, A = current.val), on=.(B = C, A), D := i.Z ]

实际上,c 在这里可以代替 cbind,但我觉得这是一种更奇怪的方法。

【讨论】:

  • 我比我现在的方法更喜欢这个。它将附加列的范围限定为它的目的。我仍然觉得我错过了一些东西,因为无法直接过滤常量
  • @Ethan 要过滤常量,我通常使用d1[.(current.val), on=.(A)]。我想最终可能会在on= 中写入一个常量,但它现在是一个相当新的功能......而且,我不确定我是否喜欢这个想法,设计方面,因为它很高兴拥有所有与x[i] 相关的数据都加入xi
  • 对。它使用:= 增加了写回的复杂性,这使得这更加复杂。我在data.table 上一直在努力解决的问题是,子集化规则在写回:= 运算符的上下文中并不总是以相同的方式工作。
  • @Ethan 我认为规则是一致的,但可能很难理解,因为子集有时是一个简单的子集,有时是一个连接。不幸的是,还没有发布连接小插图,但如果你想建立直觉,我的笔记可能会有所帮助:franknarf1.github.io/r-tutorial/_book/tables.html#tables
  • 看,我喜欢 dt,非常感谢 Matt 等人的构建以及社区的所有帮助。我想我们以前在这方面有过交集;)github.com/Rdatatable/data.table/issues/614,但我非常感谢您的见解和帮助
【解决方案2】:

只有五行,它不会有任何区别,但如果你想扩大,那么如果你在d1d2上设置键,这个操作会快得多:

d1 <- data.table(A=5:1, B=letters[5:1], key="B")
d2 <- data.table(C=letters[5:1], Z=6:10, key="C")

然后,以下构造将给出所需的结果:

d1[d1[d2][A==current.val], D := Z]

【讨论】:

  • 非常有趣的方法。我不确定 dt 如何优化交叉连接/过滤器/连接,所以我更新了示例以允许进行基准测试。解决方案(如基于初始示例所呈现)将无法通过更大的输入集完成。 d1 上的关键也确实是 A,B。也可能我搞砸了新的例子;)
  • 对于新示例(1e8 行) - 我必须将 d1 的键从 (A, B) 更改为 (B, A) 才能正常工作。通过这种更改,它会在我的系统上大约 5 秒内给出预期的结果。
  • 所以,做了一些测试。对于我的真实世界案例,我需要 A,B 的密钥。我尝试添加索引setindex(d1,B,A),但没有奏效。我真的不明白为什么它可以与 key 一起使用,但不能与 index 一起使用,但这是一个单独的问题。虽然此解决方案本身要快得多,但切换键 system.time({setkey(d1, B, A); d1[d1[d2][A == current.val], D := Z]; setkey(d1, A, B)}) 的基准与临时列方法的基准大致相同
猜你喜欢
  • 2013-01-21
  • 2016-07-20
  • 2016-04-08
  • 1970-01-01
  • 1970-01-01
  • 2017-07-08
  • 2021-10-10
相关资源
最近更新 更多