You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何删除数据框中个体首次超过指定时间阈值后的全部观测?

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()

代码解释:

  1. group_by(ID):按个体ID分组处理;
  2. which(time > threshold)[1]:找到每组中第一个time超阈值的行索引,无符合条件的行则返回NA;
  3. 将NA替换为Inf,保证全未超阈值的组中所有行都能通过row_number() < Inf的筛选;
  4. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 04:57:02