在R中为带随机中断的重复值按组进行子分组
在R中按分组实现0->24配对及单独0的子组划分
问题描述
我们有如下分组数据集:
group value 1 A 0 2 A 24 3 A 0 4 A 24 5 A 0 6 A 0 7 B 0 8 B 24 9 B 0 10 B 0 11 B 24 12 B 0
需要按group分组后,将连续的0->24配对归为同一个子组;若某个0之后没有对应的24,则该0单独成组,最终得到如下结果:
group value subgroup 1 A 0 1 2 A 24 1 3 A 0 2 4 A 24 2 5 A 0 3 6 A 0 4 7 B 0 1 8 B 24 1 9 B 0 2 10 B 0 3 11 B 24 3 12 B 0 4
数据集的可复现代码:
df <- structure(list(group = c("A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B"), value = c(0, 24, 0, 24, 0, 0, 0, 24, 0, 0, 24, 0)), class = "data.frame", row.names = c(NA, -12L))
解决方案1:使用dplyr包
通过分组标记新子组起点,再累积计数实现子组划分:
library(dplyr) df_result <- df %>% group_by(group) %>% # 标记新子组的起始行:首行或当前为0且上一行不是24时,视为新组起点 mutate( is_new_subgroup = case_when( row_number() == 1 ~ TRUE, value == 0 & lag(value) != 24 ~ TRUE, TRUE ~ FALSE ), subgroup = cumsum(is_new_subgroup) ) %>% # 将24所在行的子组编号与前一行的0保持一致 mutate(subgroup = ifelse(value == 24, lag(subgroup), subgroup)) %>% select(-is_new_subgroup) %>% ungroup() print(df_result)
逻辑说明:
- 分组处理:按
group分组,保证每个组内独立计算子组 - 标记新组起点:首行必然是新组;若当前行是
0且上一行不是24,说明该0无法和前一个24配对,需单独成组 - 累积计数:通过
cumsum对标记的新组起点计数,得到初始子组编号 - 修正24的子组编号:将
24所在行的子组编号替换为前一行0的编号,实现0->24配对同组 - 清理辅助列:移除标记用的辅助列并取消分组
解决方案2:使用data.table包(适合大数据场景)
若数据集体量较大,data.table的语法更高效:
library(data.table) setDT(df) # 分组标记新子组起点并计算初始子组编号 df[, `:=`( is_new_subgroup = shift(value, fill = -1) != 24 & value == 0 | .I == 1, subgroup = cumsum(shift(value, fill = -1) != 24 & value == 0 | .I == 1) ), by = group] # 修正24行的子组编号 df[value == 24, subgroup := shift(subgroup)] # 移除辅助列 df[, is_new_subgroup := NULL] print(df)
逻辑说明:
和dplyr方案核心逻辑一致,利用data.table的shift函数获取前一行值,通过分组操作实现高效计算。
内容的提问来源于stack exchange,提问作者Quinten
相关产品推荐
相关产品推荐

