带有条件的data.table合并与.EACHI

7
我一直在尝试使用更新的 data.table 条件合并功能,它非常酷。我有这样一种情况,有两个表 dtBigdtSmall,当进行条件合并时,这两个数据集中都存在多行匹配。是否有一种方法可以使用像 maxmin 这样的函数对这些多个匹配进行聚合?下面是一个可重现的示例,试图模拟我想要实现的内容。

设置环境

## docker run --rm -ti rocker/r-base
## install.packages("data.table", type = "source",repos = "http://Rdatatable.github.io/data.table")

创建两个虚假数据集

创建一个包含50行的“大”表格(每个ID有10个值)。

library(data.table)
set.seed(1L)

# Simulate some data
dtBig <- data.table(ID=c(sapply(LETTERS[1:5], rep, 10, simplify = TRUE)), ValueBig=ceiling(runif(50, min=0, max=1000)))
dtBig[, Rank := frank(ValueBig, ties.method = "first"), keyby=.(ID)]

    ID ValueBig Rank
 1:  A      266    3
 2:  A      373    4
 3:  A      573    5
 4:  A      909    9
 5:  A      202    2
---                 
46:  E      790    9
47:  E       24    1
48:  E      478    2
49:  E      733    7
50:  E      693    6

创建一个“小”数据集,与第一个数据集相似,但有10行(每个 ID 有2个值)。
dtSmall <- data.table(ID=c(sapply(LETTERS[1:5], rep, 2, simplify = TRUE)), ValueSmall=ceiling(runif(10, min=0, max=1000)))

    ID ValueSmall
 1:  A        478
 2:  A        862
 3:  B        439
 4:  B        245
 5:  C         71
 6:  C        100
 7:  D        317
 8:  D        519
 9:  E        663
10:  E        407

合并

我接下来想通过ID执行一次合并,只需要在ValueSmall大于或等于ValueBig时进行合并。对于匹配项,我想要获取dtBig中排名最高的值。我尝试了两种不同的方法,但是只有方法2给出了我想要的输出结果,但我不清楚为什么会有不同的输出结果。似乎它只是返回了最后一个匹配的值。

## Method 1
dtSmall[dtBig, RankSmall := max(i.Rank), by=.EACHI, on=.(ID, ValueSmall >= ValueBig)]

## Method 2
setorder(dtBig, ValueBig)
dtSmall[dtBig, RankSmall2 := max(i.Rank), by=.EACHI, on=.(ID, ValueSmall >= ValueBig)]

结果

    ID ValueSmall RankSmall RankSmall2 DesiredRank
 1:  A        478         1          4           4
 2:  A        862         1          7           7
 3:  B        439         3          4           4
 4:  B        245         1          2           2
 5:  C         71         1          1           1
 6:  C        100         1          1           1
 7:  D        317         1          2           2
 8:  D        519         3          5           5
 9:  E        663         2          5           5
10:  E        407         1          1           1

data.table中,是否有更好的方法从另一个匹配多个值的data.table中获取最大值?


更新 - 看起来与此问题相关的 data.table github 上存在问题。(github.com/Rdatatable/data.table/issues/733) - Mike.Gahan
1个回答

7
我接下来想要按照ID进行合并,仅当ValueSmall大于或等于ValueBig时才进行合并。对于匹配的结果,我希望获取dtBig中排名最高的值。
setorder(dtBig, ID, ValueBig, Rank)
dtSmall[, r :=
  dtBig[.SD, on=.(ID, ValueBig <= ValueSmall), mult="last", x.Rank ]
]

    ID ValueSmall r
 1:  A        478 4
 2:  A        862 7
 3:  B        439 4
 4:  B        245 2
 5:  C         71 1
 6:  C        100 1
 7:  D        317 2
 8:  D        519 5
 9:  E        663 5
10:  E        407 1

我想,排序dtBig并取最后匹配的行要比通过.EACHI计算max快得多,但我不是完全确定。如果您不喜欢排序,只需保存先前的排序顺序,以便以后可以恢复。


是否有一种方式可以使用类似max或min的函数对这些多个匹配进行聚合?

对于这个更一般的问题,.EACHI可以工作,只需确保您正在为目标表(在此情况下为dtSmall)的每一行进行操作,所以...

dtSmall[, r :=
  dtBig[.SD, on=.(ID, ValueBig <= ValueSmall), max(x.Rank), by=.EACHI ]$V1
]

2
由于还没有任何有关 joins 的 data.table 小册子,大家可以查看我的笔记,以更好地理解语法:http://franknarf1.github.io/r-tutorial/_book/tables.html#dt-joins(第 "updating in a join" 部分)。 - Frank
谢谢@Frank - 我没有意识到这个问题已经在这里开放了 (https://github.com/Rdatatable/data.table/issues/733)。文档非常完整! - Mike.Gahan
@Mike.Gahan 不错的发现。我知道这个问题,但以前从没想过它可以成为解决这个问题的方法。 - Frank

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接