问题 更新多行连接


在做update-join时,在哪里 i table每个键有多行,你如何控制返回哪一行?

在此示例中,update-join返回最后一行 dt2

library(data.table) 

dt1 <- data.table(id = 1) 
dt2 <- data.table(id = 1, letter = letters) 

dt1[ 
    dt2 
    , on = "id" 
    , letter := i.letter 
    ] 

dt1
#    id letter
# 1:  1      z

如何控制它返回第1行,第2行,第n行,而不是默认为最后一行?


参考

用户@Frank提供的几个与此类似的引用


5055
2018-03-15 22:02


起源

如果你排序 dt2 进入联接,你可以控制它 - dt2[order(letter,decreasing=TRUE),] 。我想这也有点灵活 - dt2[dt2[,.I[2],by="id"]$V1 ,] 例如取第二个值。但这两种情况都远非理想。 - thelatemail


答案:


我能想到的最灵活的想法是只加入一部分 dt2 其中包含您想要的行。所以,对于第二行:

dt1[ 
    dt2[, .SD[2], by=id]
    , on = "id" 
    , letter := i.letter
    ]

dt1
#   id letter
#1:  1      b

使用@Frank的帽子提示来简化子选择 dt2


6
2018-03-15 22:55



@Frank - 很好......我的印象是使用 .SD[n] 效率是禁忌。显然,这似乎已经在某个阶段进行了优化。 - thelatemail
是的,也许是部分完成的 github.com/Rdatatable/data.table/issues/735 - Frank


如何控制它返回第1行,第2行,第n行,而不是默认为最后一行?

不优雅,但有点工作:

n = 3L
dt1[, v := dt2[.SD, on=.(id), x.letter[n], by=.EACHI]$V1]

几个问题:

  1. 它不会选择使用GForce,例如,如下所示:

    > dt2[, letter[3], by=id, verbose=TRUE]
    Detected that j uses these columns: letter 
    Finding groups using forderv ... 0.020sec 
    Finding group sizes from the positions (can be avoided to save RAM) ... 0.000sec 
    lapply optimization is on, j unchanged as 'letter[3]'
    GForce optimized j to '`g[`(letter, 3)'
    Making each group and running j (GForce TRUE) ... 0.000sec 
       id V1
    1:  1  c
    
  2. 如果 n 在...之外 1:.N 对于某些加入的组,不会给出警告:

    n = 40L
    dt1[, v := dt2[.SD, on=.(id), x.letter[n], by=.EACHI]$V1]
    

或者,养成检查它的习惯 i 在更新连接中 x[i] 由连接列“键入”:

cols = "id"
stopifnot(nrow(dt2) == uniqueN(dt2, by=cols))

然后做一个不同的 i 要在适当的时候加入的表

mDT = dt2[, .(letter = letter[3L]), by=id]
dt1[mDT, on=cols, v := i.letter]

6
2018-03-15 22:45