如何在R语言中按ID删除X1=1出现后的所有行?
问题解答:按ID分组删除X1=1出现后的所有行
原始数据与目标要求
原始数据框:
df <- data.frame(ID = c(1, 1, 1, 2, 2, 2, 3, 3, 3), X1 = c(0, 1, 0, 0, 1, 0, 0, 0, 1))
想要得到的目标数据框:
df1 <- data.frame(ID = c(1, 1, 2, 2, 3, 3, 3), X1 = c(0, 1, 0, 1, 0, 0, 1))
需求:按ID分组,每个组仅保留X1=1第一次出现的位置及之前的所有行,删除第一次出现X1=1之后的所有行。
你的尝试代码问题
你编写的这段代码:
df1 <- df %>% group_by(ID) %>% mutate(flag = cumsum(X1 == 1)) %>% filter(flag <= 1)
无法满足需求。原因是cumsum(X1 == 1)会累计统计X1=1的出现次数,比如ID=1的组中第三行X1=0对应的flag值为1(前面已出现过一次X1=1),filter(flag <=1)会保留这一行,但按照需求该行应该被删除,最终结果和目标df1不符。
正确的实现方式
这里提供两种可靠的实现方法:
方法一:定位第一个X1=1的位置截取行
library(dplyr) df1 <- df %>% group_by(ID) %>% # 找到第一个X1=1的行号,若无则保留所有行 slice(1:ifelse(any(X1 == 1), which.max(X1 == 1), n())) %>% ungroup()
which.max(X1 == 1)会返回组内第一个X1=1的行索引,any(X1 == 1)判断组内是否存在X1=1,不存在则保留全部行。
方法二:用cumany和lag实现简洁过滤
library(dplyr) df1 <- df %>% group_by(ID) %>% # 过滤掉第一次出现X1=1之后的所有行 filter(!cumany(lag(X1 == 1, default = FALSE))) %>% ungroup()
原理:lag(X1 == 1)获取当前行的前一行是否为X1=1,cumany会将逻辑值累计传递——只要前一行出现过X1=1,后续所有行的cumany结果都会为TRUE,取反后即可过滤掉这些行,正好保留到第一次出现X1=1的位置。
两种方法都能得到与目标df1完全一致的结果。
内容的提问来源于stack exchange,提问作者bvowe
相关产品推荐
相关产品推荐

