对于每个组,选择第一行,然后选择与条件匹配的另一行

时间:2019-09-25 21:30:12

标签: r data.table

假设我有以下data.table:

x <- data.table(a = c(1, 3, 2, 2, 4, 3, 7, 10, 9, 8),
                b = c(1, 1, 1, 2, 2, 2, 2, 3, 3, 3))

然后,按b分组后,我要选择以下行:

  • 是该组的第一行
  • 该组中最高的a

如果单行同时满足这两个条件,则应只选择一次(该组将只包含一行)。

这些选择中的每一个都是微不足道的:

x[, .SD[1], by = b]  # selects first row per group
#    b  a
# 1: 1  1
# 2: 2  2
# 3: 3 10

x[, .SD[which.max(a)], by = b]  # selects row with the highest 'a' in the group
#    b  a
# 1: 1  3
# 2: 2  7
# 3: 3 10

但是我不知道如何一次完成这两项操作(显然.SD[1 | which.max(a)]无效)。我可以分别执行它们,然后rbindlist得到最终结果,但是我想知道是否有更简单的方法。

为清楚起见,在上述情况下,预期输出为(也可以接受不同顺序):

   b  a
1: 1  1
2: 1  3
3: 2  2
4: 2  7
5: 3 10

3 个答案:

答案 0 :(得分:3)

一个选项是将索引1(对于第一行)与which.max串联在一起-还返回一个数字索引,然后取其中的unique(如果相同的值1为由which.max返回,并使用它来子集化data.table(.SD

x[, .SD[unique(c(1, which.max(a)))], by = b]
#   b  a
#1: 1  1
#2: 1  3
#3: 2  2
#4: 2  7
#5: 3 10

或使用.I

x[x[, .I[unique(c(1, which.max(a)))], by = b]$V1]

答案 1 :(得分:1)

这是我在dplyr中的做法:

library(dplyr)
x <- data.frame(a = c(1, 3, 2, 2, 4, 3, 7, 10, 9, 8),
                b = c(1, 1, 1, 2, 2, 2, 2, 3, 3, 3))

x %>% group_by(b) %>% filter(row_number() == 1 | a == max(a))

输出

#   a  b
#1: 1  1
#2: 3  1
#3: 2  2
#4: 7  2
#5: 10 3

答案 2 :(得分:1)

如果只有这两列,只需合并两个表:

funion(
  x[, lapply(.SD, max), by=b],
  x[, lapply(.SD, first), by=b]
)

我认为max值比您的which.max效率更高,因为它已经过优化(请参见?GForce)。