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

在R中筛选每个个体首次出现非连续年份前的所有行

问题描述

数据集

我在R中有如下数据集:

name = c("john", "john", "john", "john", "john", "alex", "alex", "alex", "alex", "alex" )
year = c(2010, 2011, 2012, 2015, 2017, 2014, 2015, 2016, 2017, 2018)
my_data = data.frame(name, year)

输出结果:

> my_data
   name year
1  john 2010
2  john 2011
3  john 2012
4  john 2015
5  john 2017
6  alex 2014
7  alex 2015
8  alex 2016
9  alex 2017
10 alex 2018

需求

为数据集中的每个个体,筛选出首次出现非连续年份之前的所有行。期望输出如下:

# DESIRED OUTPUT
> my_data
   name year
1  john 2010
2  john 2011
3  john 2012
6  alex 2014
7  alex 2015
8  alex 2016
9  alex 2017
10 alex 2018

尝试的方法

我尝试了以下方法:

agg <- aggregate(year ~ name, my_data, c)
agg
#   name year.1 year.2 year.3 year.4 year.5
# 1 alex   2014   2015   2016   2017   2018
# 2 john   2010   2011   2012   2015   2017

library(stringr)
agg = data.frame(as.matrix(agg))
agg$all_years = paste(agg$year.1 ,agg$year.2,  agg$year.3, agg$year.4, agg$year.5)

agg$y_2010 = str_detect(agg$all_years, "2010")
agg$y_2011 = str_detect(agg$all_years, "2011")
agg$y_2012 = str_detect(agg$all_years, "2012")
agg$y_2013 = str_detect(agg$all_years, "2013")
agg$y_2014 = str_detect(agg$all_years, "2014")
agg$y_2015 = str_detect(agg$all_years, "2015")
agg$y_2016 = str_detect(agg$all_years, "2016")
agg$y_2017 = str_detect(agg$all_years, "2017")
agg$y_2018 = str_detect(agg$all_years, "2018")
agg$y_2019 = str_detect(agg$all_years, "2019")

输出结果:

name year.1 year.2 year.3 year.4 year.5                all_years y_2010 y_2011 y_2012 y_2013 y_2014 y_2015 y_2016 y_2017 y_2018 y_2019
1 alex   2014   2015   2016   2017   2018 2014 2015 2016 2017 2018  FALSE  FALSE  FALSE  FALSE   TRUE   TRUE   TRUE   TRUE   TRUE  FALSE
2 john   2010   2011   2012   2015   2017 2010 2011 2012 2015 2017   TRUE   TRUE   TRUE  FALSE  FALSE   TRUE  FALSE   TRUE  FALSE  FALSE

我的思路是找出每行中首次出现“TRUE”后接“FALSE”的位置,但不确定后续如何操作,请求指导完成该需求。


解决方案

你的思路方向没错,但现有方法太繁琐,其实可以直接对每个个体的年份序列计算相邻差值,找到首次出现非1的位置,然后保留该位置之前的所有行。以下是两种更高效的实现方式:

方法1:基础R实现

# 按name分组处理
result <- do.call(rbind, lapply(split(my_data, my_data$name), function(df) {
  # 计算相邻年份的差值
  diffs <- diff(df$year)
  # 找到第一个差值不等于1的位置,若全部连续则返回所有行
  first_break <- which(diffs != 1)[1]
  if (is.na(first_break)) {
    df
  } else {
    df[1:first_break, ]
  }
}))

# 重置行名(可选)
rownames(result) <- NULL
result

输出结果:

name year
1  alex 2014
2  alex 2015
3  alex 2016
4  alex 2017
5  alex 2018
6  john 2010
7  john 2011
8  john 2012

方法2:dplyr包实现(更简洁)

如果你习惯用tidyverse工具链,可以用dplyr分组处理:

library(dplyr)

result <- my_data %>%
  group_by(name) %>%
  # 标记当前年份与下一年份是否连续,最后一行设为TRUE(因为没有下一年)
  mutate(is_continuous = ifelse(row_number() == n(), TRUE, year + 1 == lead(year))) %>%
  # 找到首次不连续的位置,保留之前的所有行
  filter(cumall(is_continuous)) %>%
  select(-is_continuous) %>%
  ungroup()

result

输出结果和基础R方法一致。

方法说明

两种方法的核心逻辑都是:

  • 按name分组,获取每个个体的年份序列
  • 检查年份是否连续(相邻年份差值为1)
  • 找到首次出现不连续的位置,保留该位置及之前的所有行(如果全部连续则保留所有行)

这种方法比字符串检测方式更直接,不需要手动创建年份列,也能适配任意年份范围。

内容的提问来源于stack exchange,提问作者stats_noob

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 17:55:29