如何删除数据框中个体首次超过指定时间阈值后的全部观测?
R语言按ID筛选观测:基于首次超过阈值的规则删除行
需求说明
针对按ID分组的多行观测数据,需按以下规则筛选:
- 若某个体的
time值首次超过预设阈值,删除该个体此观测之后的所有行; - 若个体的首个观测就超过阈值,删除该个体全部观测;
- 所有
time均未超过阈值的个体,保留全部观测。
示例数据
ID <- c(1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,7,7) time <- c(20,23,11,14,15,31, 14, 21, 7, 11, 45, 21, 35, 2, 90, 36, 18, 3, 35, 10, 5,19, 27, 12, 51,91,4,13,9,12,10,7,8,15,6,16) sim_dat <- data.frame(ID, time)
解决方案1:使用dplyr(tidyverse风格)
借助分组操作和行号判断实现规则:
library(dplyr) threshold <- 30 filtered_dat <- sim_dat %>% group_by(ID) %>% mutate( # 定位每个组中首次超过阈值的行号,无则返回NA first_over = which(time > threshold)[1], # 将NA替换为Inf,确保全未超阈值的组保留所有行 first_over = ifelse(is.na(first_over), Inf, first_over) ) %>% # 筛选条件:行号小于首次超阈值的行号(全未超则行号均<Inf) filter(row_number() < first_over) %>% select(-first_over) %>% # 移除辅助计算列 ungroup()
代码解释:
group_by(ID):按个体ID分组处理;which(time > threshold)[1]:找到每组中第一个time超阈值的行索引,无符合条件的行则返回NA;- 将
NA替换为Inf,保证全未超阈值的组中所有行都能通过row_number() < Inf的筛选; filter(row_number() < first_over):- 若首个观测就超阈值,
first_over=1,无行满足筛选条件,自动删除整个组; - 若首次超阈值在第k行,保留前k-1行;
- 全未超阈值则保留所有行。
- 若首个观测就超阈值,
解决方案2:使用Base R
无需加载第三方包,通过拆分-处理-合并实现:
threshold <- 30 # 按ID拆分数据框 split_dat <- split(sim_dat, sim_dat$ID) # 逐个处理每个ID组 processed_dat <- lapply(split_dat, function(df) { first_over <- which(df$time > threshold)[1] if (is.na(first_over)) { # 全未超阈值,保留原数据 df } else if (first_over == 1) { # 首个观测就超阈值,返回空数据框(即删除该组) data.frame() } else { # 保留首次超阈值之前的所有行 df[1:(first_over - 1), ] } }) # 合并所有处理后的组,并重置行名 filtered_dat_base <- do.call(rbind, processed_dat) rownames(filtered_dat_base) <- NULL
结果验证
查看筛选后各ID的观测数量:
table(filtered_dat$ID)
输出结果符合预期:
1 2 4 6 7 5 2 5 3 2
(ID3和ID5因首个观测超阈值被全部删除,其余ID按规则保留对应行)
内容的提问来源于stack exchange,提问作者Stella
相关产品推荐
相关产品推荐

