当值大于...减 2 时删除每个 ID 的行

Deleting Rows per ID when value gets greater than... minus 2

我有以下数据框

id<-c(1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3)
time<-c(0,1,2,3,4,5,6,7,0,1,2,3,0,1,2,3)
value<-c(1,1,6,1,2,0,0,1,2,6,2,2,1,1,6,1)

d<-data.frame(id, time, value)

值 6 对于每个 id 只出现一次。对于每个 id,我想删除每个 id 值为 6 的行之后的所有行,除了后面的前两行。

我搜索了一下,发现了一个类似的问题,但是我自己无法适应。因此我使用 code of this thread

在上述情况下,最终数据帧应该是

id  time value
1    0     1
1    1     1
1    2     6
1    3     1
1    4     2
2    0     2
2    1     6
2    2     2
2    3     2
3    0     1
3    1     1
3    2     6
3    3     1

给出的解决方案中有一个似乎非常接近我需要的。但我没能适应它。你能帮帮我吗?

library(plyr)

ddply(d, "id", 
      function(x) {
        if (any(x$value == 6)) {
          subset(x, time <= x[x$value == 6, "time"])
        } else {
          x
        }
      }
)

非常感谢。

我们可以使用 data.table。将 'data.frame' 转换为 'data.table' (setDT(d))。按 'id' 列分组,我们得到 'value' 的位置等于 6。向其添加 2。找到该组 (.N) 的元素数量 min 和位置,得到 seq,并使用它来对数据集进行子集化。我们还可以添加一个if/else条件来检查'value'列中是否有any6或else到return.SD而不进行任何子集化.

library(data.table)
setDT(d)[, if(any(value==6)) .SD[seq(min(c(which(value==6) + 2, .N)))] 
                  else .SD, by = id]
#     id time value
# 1:  1    0     1
# 2:  1    1     1
# 3:  1    2     6
# 4:  1    3     1
# 5:  1    4     2
# 6:  2    0     2
# 7:  2    1     6
# 8:  2    2     2
# 9:  2    3     2
#10:  3    0     1
#11:  3    1     1
#12:  3    2     6
#13:  3    3     1
#14:  4    0     1
#15:  4    1     2
#16:  4    2     5

或者正如@Arun 在评论中提到的,我们可以使用 ?head 进行子集化,这样会更快

setDT(d)[, if(any(value==6)) head(.SD, which(value==6L)+2L) else .SD, by = id]

或者使用 dplyr,我们按 'id' 分组,得到 'value' 6 的位置 which,加上 2,得到 seq 和使用 slice 中的数字索引来提取行。

library(dplyr)
d %>%
   group_by(id) %>%
   slice(seq(which(value==6)+2))
#   id time value
#1   1    0     1
#2   1    1     1
#3   1    2     6
#4   1    3     1
#5   1    4     2
#6   2    0     2
#7   2    1     6
#8   2    2     2
#9   2    3     2
#10  3    0     1
#11  3    1     1
#12  3    2     6
#13  3    3     1
#14  4    0     1
#15  4    1     2
#16  4    2     5

数据

d <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 
3L, 3L, 3L, 4L, 4L, 4L), time = c(0L, 1L, 2L, 3L, 4L, 0L, 1L, 
2L, 3L, 0L, 1L, 2L, 3L, 0L, 1L, 2L), value = c(1L, 1L, 6L, 1L, 
2L, 2L, 6L, 2L, 2L, 1L, 1L, 6L, 1L, 1L, 2L, 5L)), .Names = c("id", 
"time", "value"), class = "data.frame", row.names = c(NA, -16L))