我有一个包含几列的数据框。基于“activity”列,我想删除特定值“pt”的整个连续运行,但前提是它们紧邻“outside”运行之前或之后发生。
在下面的简化数据中,有一次运行的“activity”为“outside”,并且前后都有大块“pt”。这两个“pt” block 应该被删除。
activity dist
1 home 1
2 pt 2 # <- run of 'pt' before run of 'outside': remove
3 pt 3 # <-
4 pt 4 # <-
5 outside 5
6 outside 6
7 pt 7 # <- run of 'pt' after run of 'outside': remove
8 pt 8 # <-
9 work 9
10 pt 10
11 pt 11
12 home 12
因此,所需的输出是:
activity dist
1 home 1
2 outside 5
3 outside 6
4 work 9
5 pt 10
6 pt 11
7 home 12
如何实现这一目标?
数据的dput
:
structure(list(activity = c("home", "pt", "pt", "pt", "outside", "outside", "pt", "pt", "work", "pt", "pt", "home"),
dist = 1:12),
class = "data.frame", row.names = c(NA, -12L))
最佳答案
您可以使用 data.table
中的一些便捷功能封装:rleid
“[g]生成游程类型组 ID”,以及 shift
获取向量中焦点索引之前和之后的值。
library(data.table)
setDT(d)
d[ , r := rleid(activity)]
d[!(r %in% r[activity == "pt" & shift(activity, type = "lead") == "outside" |
shift(activity) == "outside" & activity == "pt"])]
# activity dist r
# 1: home 1 1
# 2: outside 5 3
# 3: outside 6 3
# 4: work 9 5
# 5: pt 10 6
# 6: pt 11 6
# 7: home 12 7
说明:
强制你的data.frame
到 data.table
(setDT(d)
)。创建“事件”的游程长度索引 ( rleid
)。检查当前值为“pt”且下一个值是否为“outside”( activity == "pt" & shift(activity, type = "lead") == "outside"
),或者如果当前值为“pt”且上一个值为“outside”( |
),则检查( activity == "pt" & shift(activity) == "outside"
)。
这个条件是TRUE
,获取要删除的运行组 ( r[<condition>]
)。检查运行是否在要删除的组中 ( r %in% <run groups to be removed>
)。如果是这样,则在对数据建立索引 ( !
) 时不要 ( d[<condition>]
) 保留这些行
base
替代使用 rle
.
“outside”之前或之后的“pt”游程值替换为 NA
。 rle 被转换回向量 ( inverse.rle
) 和包含 NA
的行已删除 ( na.omit
)。
显然,如果有NA
的行在要保留的原始数据集中,需要使用另一个值进行替换。
with(rle(d$activity),
values[c(which(head(values, -1) == "pt" & tail(values, -1) == "outside"),
which(head(values, -1) == "outside" & tail(values, -1) == "pt") + 1)]) <- NA
d$activity = inverse.rle(r)
na.omit(d)
关于r - 删除特定值之前和之后的特定值的运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62454188/