R语言按Grp分组在Treat状态切换时生成连续计数序列列的实现
实现方案
核心逻辑:按Grp分组、按Year升序排序后,通过连续运行长度(RLE)识别每一段连续相同的Treat值,对非零的连续段从1开始累计计数,Treat为0时直接赋值为0。
方案1:dplyr 实现(简洁易读,日常开发首选)
library(dplyr) df_result <- df %>% # 按分组、年份排序保证顺序符合要求 arrange(Grp, Year) %>% group_by(Grp) %>% mutate( treat_rle = rle(Treat), # 对每个连续Treat段生成从1开始的累计序号 seq = ifelse(Treat == "0", 0, sequence(treat_rle$lengths)) ) %>% # 移除中间计算用的rle对象列 select(-treat_rle) %>% ungroup()
方案2:基础R实现(无依赖,适配所有R环境)
# 先按分组、年份排序 df <- df[order(df$Grp, df$Year), ] # 初始化seq列 df$seq <- 0 # 逐组处理 for (group in unique(df$Grp)) { row_idx <- df$Grp == group current_treat <- df$Treat[row_idx] # 计算连续值的运行长度 rle_lengths <- rle(current_treat)$lengths # 生成连续段的累计计数 current_seq <- sequence(rle_lengths) # 将Treat为0的位置赋值为0 current_seq[current_treat == "0"] <- 0 # 结果写回数据框 df$seq[row_idx] <- current_seq }
方案3:data.table实现(高性能,适配大数据量场景)
library(data.table) # 转换为data.table格式 setDT(df) df[order(Grp, Year), seq := { current_treat <- Treat rle_lengths <- rle(current_treat)$lengths s <- sequence(rle_lengths) s[current_treat == "0"] <- 0 .(s) }, by = Grp]
注意:原始数据中
Treat字段为字符型,判断零值时统一与字符"0"比较,直接与数值0比较会出现逻辑判断错误。
内容的提问来源于stack exchange,提问作者Chuan
相关产品推荐
相关产品推荐

