在data.table中使用ifelse为每个组选择一行

Ste*_* J. 17 r data.table

我正在对data.table进行分组,并希望从每个组中选择x == 1的第一行,或者如果这样的行不存在,那么第一行中的任何值都是x

d <- data.table(
           a = c(1,1,1,  2,2,  3,3), 
           x = c(0,1,0,  0,0,  1,1), 
           y = c(1,2,3,  1,2,  1,2)
)
Run Code Online (Sandbox Code Playgroud)

这种尝试

d[, ifelse(any(.SD[,x] == 1),.SD[x == 1][1], .SD[1]), by = a]
Run Code Online (Sandbox Code Playgroud)

回报

   a V1
1: 1  1
2: 2  0
3: 3  1
Run Code Online (Sandbox Code Playgroud)

但我期待

   a  x  y
1: 1  1  2
2: 2  0  1
3: 3  1  1
Run Code Online (Sandbox Code Playgroud)

任何想法如何正确吗?

Dav*_*urg 15

我认为这对两者都是一个很好的用例,match 而且它的nomatch论点

d[, .SD[match(1L, x, nomatch = 1L)], by = a]
#    a x y
# 1: 1 1 2
# 2: 2 0 1
# 3: 3 1 1
Run Code Online (Sandbox Code Playgroud)

基本上,如果不匹配,则返回1,结果为您提供组中的第一行.如果存在多重匹配,那么它将根据您的愿望返回第一个匹配


edd*_*ddi 15

另一种选择(which.max基本上设计为完全按照你的意愿):

d[, .SD[which.max(x == 1)], by = a]
#   a x y
#1: 1 1 2
#2: 2 0 1
#3: 3 1 1
Run Code Online (Sandbox Code Playgroud)


akr*_*run 6

我们也可以这样做.I来返回行索引并使用它来对行进行子集化.

d[d[, .I[which.max(x==1)], by = a]$V1]
#   a x y
#1: 1 1 2
#2: 2 0 1
#3: 3 1 1
Run Code Online (Sandbox Code Playgroud)

在当前版本中data.table,.I.SD子集化行相比,方法更有效(但是,它可能在将来发生变化).这也是一个类似的帖子


这是另一个选项order(setkey也可以用于 - 效率)数据集'a'和'x'分组后'a',然后得到第一行head

d[order(a ,-x), head(.SD, 1) ,by = a]
#   a x y
#1: 1 1 2
#2: 2 0 1
#3: 3 1 1
Run Code Online (Sandbox Code Playgroud)

基准

最初,我们考虑在> 1e6上进行基准测试,但这些.SD方法需要时间,所以比较使用的3e5data.table_1.9.7

set.seed(24)
d1 <- data.table(a = rep(1:1e5, 3), x = sample(0:1, 1e5*3, 
           replace=TRUE), y = rnorm(1e5*3))

system.time(d1[, .SD[which.max(x == 1)], by = a])
#   user  system elapsed 
#  56.21   30.64   86.42 

system.time(d1[, .SD[match(1L, x, nomatch = 1L)], by = a])
# user  system elapsed 
#  55.27   30.07   83.75 

system.time(d1[d1[, .I[which.max(x==1)], by = a]$V1])
#  user  system elapsed 
#   0.19    0.00    0.19 


system.time(d1[order(a ,-x), head(.SD, 1) ,by = a])
# user  system elapsed 
#   0.03    0.00    0.04 
Run Code Online (Sandbox Code Playgroud)

  • 来自http://stackoverflow.com/a/16574176/的一个熟悉的变体可能值得一提的是可能的性能提升与.SD [stuff]方式相比. (4认同)
  • 无论如何,你的回答只是两个eddis答案的逐字记录.我不认为你应该把它作为你自己发布. (4认同)
  • 是的,我认为没有人会相信你会逐字复制它.我们已经内化了这个成语并在我们的答案和工作中多次使用它,我想(虽然我总是试图引用原文,因为我确信我自己从来没有想过它). (2认同)