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

时间:2015-08-26 11:33:21

标签: r row

我有以下数据框

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)

每个ID只显示一次值6。对于每个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
        }
      }
)

非常感谢。

1 个答案:

答案 0 :(得分:4)

我们可以使用data.table。将'data.frame'转换为'data.table'(setDT(d))。通过'id'列分组,我们得到'value'的位置等于6.为它添加2。找到该组元素数量的min(.N)和位置,获取seq,然后使用它来对数据集进行子集化。我们还可以添加if/else条件来检查“值”列中是否any 6还是else以返回.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'分组,使用which获取'value'的位置,添加2,获取seq并在slice内使用该数字索引{1}}提取行。

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))