如何基于tidyverse高效更新Sequ的游程长度ID并跳过NA
纯tidyverse实现游程ID生成(跳过NA)
给定数据集:
df <- data.frame( ID = 1:10, Sequ = c(NA, 44,44, NA, NA, 33,33,33, 5,5), Q = c(NA, "q1","q1", NA, NA, "q2","q2","q2", "q2","q2") )
原方案借助data.table::rleid结合dplyr实现了需求,这里提供纯tidyverse的替代方案,无需依赖data.table:
library(dplyr) df_processed <- df %>% mutate( # 标记非NA的行 non_na_flag = !is.na(Sequ), # 判断当前非NA行是否属于新的游程组 is_new_group = non_na_flag & (Sequ != lag(Sequ, default = first(Sequ[non_na_flag]))), # 生成游程ID,NA位置保留NA Sequ_0 = ifelse(non_na_flag, cumsum(is_new_group), NA_integer_) ) %>% # 清理临时辅助列 select(-non_na_flag, -is_new_group, -Sequ) print(df_processed)
执行后输出:
ID Q Sequ_0 1 1 <NA> NA 2 2 q1 1 3 3 q1 1 4 4 <NA> NA 5 5 <NA> NA 6 6 q2 2 7 7 q2 2 8 8 q2 2 9 9 q2 3 10 10 q2 3
逻辑说明
non_na_flag:先标记出Sequ列非NA的行,后续只对这些行处理;is_new_group:判断当前非NA行是否开启了新游程——当当前行非NA,且与前一个非NA行的Sequ值不同时,标记为新组;Sequ_0:用cumsum对新组标记求和,得到递增的游程ID,再通过ifelse把原NA的位置设回NA;- 最后清理掉临时辅助列,得到目标结果。
这个方案完全基于tidyverse工具链,逻辑直观,不需要跨包依赖,对于常规规模的数据集效率表现优异。
内容的提问来源于stack exchange,提问作者Chris Ruehlemann
相关产品推荐
相关产品推荐

