R语言为dataframe按连续时间段分组添加正确索引列
问题原因
你之前用的dense_rank(gp)是对gp列的所有取值做全局排序编号,完全不考虑记录的先后顺序和连续出现逻辑,因此所有取值为group1的记录都会被分配同一个编号,无法区分被其他分组打断的非连续同组时段。
要实现连续同组段的独立索引,核心逻辑是按行顺序判断当前行的分组是否和上一行不同,每发生一次分组切换,索引值加1,两种常用实现方式如下:
实现方法
方法1:使用rleid()(最简便)
data.table包的rleid()函数是专门为「连续相同值生成序列id」设计的,和需求完全匹配,直接调用即可:
library(tidyverse) library(data.table) # 构造示例数据 date<-as.Date(c('2022-05-02','2022-05-09', '2022-05-16', '2022-05-23', '2022-05-30','2022-06-06','2022-06-13','2022-06-20')) gp<-c( "group1","group1", "group2","group2","group3","group3","group1","group1") index<-c(1,1,2,2,3,3,4,4) data<-data.frame(date,gp,index, stringsAsFactors = FALSE) # 生成正确索引 data <- data %>% mutate(correct_index = rleid(gp))
运行后correct_index列的值和预期的index列完全一致。
方法2:纯dplyr实现(无需额外加载包)
如果不想依赖data.table,可以用lag()取上一行分组值,配合cumsum()累加分组切换的次数实现:
data <- data %>% # 若数据未按日期排序,先执行 arrange(date) 保证顺序正确 mutate(correct_index = cumsum(gp != lag(gp, default = first(gp))) + 1)
逻辑说明:
lag(gp, default = first(gp)):取上一行的分组值,第一行没有上一行时默认取第一行的分组值,避免出现NAgp != lag(...):判断当前行分组是否和上一行不同,不同返回TRUE(等价于数值1),相同返回FALSE(等价于数值0)cumsum() + 1:对上述判断结果累加,每发生一次分组切换计数加1,初始值从1开始计数,最终得到每个连续段的独立索引
注意事项
生成索引前必须保证数据是按时间顺序排列的,否则连续段的判断会出错,若原始数据未排序,在mutate前加arrange(date)即可。
内容的提问来源于stack exchange,提问作者Basil
相关产品推荐
相关产品推荐

