如何使用dplyr按ID保留首次出现grade 5及之前的所有记录?
问题:按ID分组保留首次出现grade 5及之前的记录
示例数据集
ID grade date A 1 1/1/2001 A 3 1/2/2002 A 5 2/4/2002 B 4 1/1/2008 B 4 1/1/2010 B 5 1/1/2011 B 5 1/3/2011 B 4 1/5/2011 C 2 1/1/2006 C 5 1/1/2007 C 5 1/1/2008 D 3 1/1/1996 D 5 1/1/1997 D 5 1/1/1999 E 1 1/1/2003 E 3 1/1/2005 E 3 1/1/2007
需求说明
按ID分组后,对每个ID执行以下规则:
- 保留首次出现grade=5及之前的所有条目,忽略该条之后的所有记录
- 若ID从未出现grade=5,则保留全部条目
期望输出
ID grade date A 1 1/1/2001 A 3 1/2/2002 A 5 2/4/2002 B 4 1/1/2008 B 4 1/1/2010 B 5 1/1/2011 C 2 1/1/2006 C 5 1/1/2007 D 3 1/1/1996 D 5 1/1/1997 E 1 1/1/2003 E 3 1/1/2005 E 3 1/1/2007
解决方案(使用dplyr)
通过dplyr的分组定位+过滤逻辑可以实现需求,代码如下:
library(dplyr) # 构建示例数据集(假设原数据集名为df) df <- data.frame( ID = c("A", "A", "A", "B", "B", "B", "B", "B", "C", "C", "C", "D", "D", "D", "E", "E", "E"), grade = c(1, 3, 5, 4, 4, 5, 5, 4, 2, 5, 5, 3, 5, 5, 1, 3, 3), date = c("1/1/2001", "1/2/2002", "2/4/2002", "1/1/2008", "1/1/2010", "1/1/2011", "1/3/2011", "1/5/2011", "1/1/2006", "1/1/2007", "1/1/2008", "1/1/1996", "1/1/1997", "1/1/1999", "1/1/2003", "1/1/2005", "1/1/2007") ) # 核心处理逻辑 result <- df %>% group_by(ID) %>% # 定位每个组内首次出现grade=5的行号,无则取组内总行数 mutate(first_5_pos = ifelse(any(grade == 5), min(which(grade == 5)), n())) %>% # 保留首次grade=5及之前的所有行 filter(row_number() <= first_5_pos) %>% # 清理临时辅助列并取消分组 select(-first_5_pos) %>% ungroup() print(result)
代码逻辑解释
group_by(ID):按ID分组,确保每个ID的记录单独处理mutate(first_5_pos = ...):- 用
any(grade == 5)判断当前组是否存在grade=5的记录 - 存在则用
min(which(grade == 5))取首次出现的行号;不存在则取组内总行数n()
- 用
filter(row_number() <= first_5_pos):保留行号小于等于目标行号的所有记录select(-first_5_pos)与ungroup():删除临时计算列并取消分组,还原常规数据结构
内容的提问来源于stack exchange,提问作者tacrolimus
相关产品推荐
相关产品推荐

