如何在R中为无NA且含指定类别的3行创建非重叠分组列
解决分组数据框的滚动窗口不重叠标记问题
示例数据构造
先构造一个和你场景匹配的示例数据,方便测试:
library(dplyr) library(purrr) set.seed(123) df <- tibble( id = rep(c("A", "B"), each = 10), category = sample(c("Apple", "Banana", "Orange", NA), 20, replace = TRUE), value = ifelse(is.na(category), NA, rnorm(20)) )
核心解决方案代码
以下代码实现每个id分组内的不重叠滚动窗口检查与标记:
df_processed <- df %>% group_by(id) %>% mutate(row_idx = row_number()) %>% group_split() %>% map_dfr(function(group) { total_rows <- nrow(group) group$group_label <- NA_character_ group_counter <- 1 current_pos <- 1 while (current_pos <= total_rows - 2) { # 截取当前3行窗口 window_slice <- slice(group, current_pos:(current_pos + 2)) # 验证窗口条件:无NA值,且包含全部三类category valid_window <- all(!is.na(window_slice$value)) && all(c("Apple", "Banana", "Orange") %in% window_slice$category) if (valid_window) { # 给窗口内3行添加标签 label <- paste0(group$id[1], "_group_", group_counter) group$group_label[current_pos:(current_pos + 2)] <- label # 跳过已标记行,保证分组不重叠 current_pos <- current_pos + 3 group_counter <- group_counter + 1 } else { # 步长1,检查下一个窗口 current_pos <- current_pos + 1 } } group %>% select(-row_idx) }) %>% ungroup()
代码逻辑说明
- 分组与行号标记:先按
id分组,给每组内的行添加行号,方便窗口定位 - 逐组处理:用
group_split拆分每个id的独立数据框,再用map_dfr循环处理每组 - 滚动窗口检查:用
while循环遍历行,每次检查当前位置开始的3行窗口:- 若窗口满足「无NA值」且「包含全部三个category」,则给这3行打上指定格式的标签
- 标记完成后直接跳过这3行(步长3),确保分组不重叠;不满足则步长1继续检查下一个窗口
- 结果合并:处理完所有组后合并为最终数据框,去掉临时行号列
为什么之前的方法没解决?
expand.grid和转宽表更适合静态的多值匹配,难以处理「滚动+不重叠」的动态遍历逻辑zoo::rollapply能实现滚动窗口计算,但默认是滑动遍历(步长1),无法直接跳过已匹配的行来保证分组不重叠,需要额外的循环逻辑配合
查看处理结果
运行以下代码查看最终标记效果:
print(df_processed, n = 20)
内容的提问来源于stack exchange,提问作者cebola
相关产品推荐
相关产品推荐

