当值大于...减 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'列中是否有any
6或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))
我有以下数据框
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'列中是否有any
6或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))