如何用dplyr的mutate和case_when实现嵌套条件分组标记?
问题描述
我有一个每个ID对应多条观测数据的数据框,每个ID完成了多项测试,每项测试根据表现被分为三分位排名(top、mid、bottom),排名会随时间点变化。
示例数据框
df <- tibble( ID = c(1,1,1,2,2,2,3,3,3,4,4,4), time = c(1,2,3,1,2,3,1,2,3,1,2,3), test1_rank = c("top", "top", "top", "top", "mid", "bottom", "bottom", "bottom", "bottom", "top", "bottom", "bottom"), test2_rank = c("bottom", "bottom", "bottom", "top", "mid", "bottom", "top", "top", "top", "top", "bottom", "bottom") )
数据预览:
| ID | time | test1_rank | test2_rank |
|---|---|---|---|
| 1 | 1 | top | bottom |
| 1 | 2 | top | bottom |
| 1 | 3 | top | bottom |
| 2 | 1 | top | top |
| 2 | 2 | mid | mid |
| 2 | 3 | bottom | bottom |
| 3 | 1 | bottom | top |
| 3 | 2 | bottom | top |
| 3 | 3 | bottom | top |
| 4 | 1 | top | top |
| 4 | 2 | bottom | bottom |
| 4 | 3 | bottom | bottom |
分类规则
- 若三个时间点排名一致,标记为
"stable(top)"或"stable(bottom)"(根据排名是top还是bottom); - 若排名从time1的top变为time2的mid再变为time3的bottom,标记为
"gradual"; - 若排名从time1的top直接变为time2和time3的bottom,标记为
"rapid"; - 其他组合标记为
"Other"。
期望结果
df2 <- tibble( ID = c(1,1,1,2,2,2,3,3,3,4,4,4), time = c(1,2,3,1,2,3,1,2,3,1,2,3), test1_rank = c("top", "top", "top", "top", "mid", "bottom", "bottom", "bottom", "bottom", "top", "bottom", "bottom"), test2_rank = c("bottom", "bottom", "bottom", "top", "mid", "bottom", "top", "top", "top", "top", "bottom", "bottom"), test1_rankgroup = c("stable(top)", "stable(top)", "stable(top)", "gradual", "gradual", "gradual", "stable(bottom)", "stable(bottom)", "stable(bottom)", "rapid", "rapid", "rapid"), test2_rankgroup = c("stable(bottom)", "stable(bottom)", "stable(bottom)", "gradual", "gradual", "gradual", "stable(top)", "stable(top)", "stable(top)", "rapid", "rapid", "rapid") )
数据预览:
| ID | time | test1_rank | test2_rank | test1_rankgroup | test2_rankgroup |
|---|---|---|---|---|---|
| 1 | 1 | top | bottom | stable(top) | stable(bottom) |
| 1 | 2 | top | bottom | stable(top) | stable(bottom) |
| 1 | 3 | top | bottom | stable(top) | stable(bottom) |
| 2 | 1 | top | top | gradual | gradual |
| 2 | 2 | mid | mid | gradual | gradual |
| 2 | 3 | bottom | bottom | gradual | gradual |
| 3 | 1 | bottom | top | stable(bottom) | stable(top) |
| 3 | 2 | bottom | top | stable(bottom) | stable(top) |
| 3 | 3 | bottom | top | stable(bottom) | stable(top) |
| 4 | 1 | top | top | rapid | rapid |
| 4 | 2 | bottom | bottom | rapid | rapid |
| 4 | 3 | bottom | bottom | rapid | rapid |
请问在dplyr中使用mutate和case_when实现该需求的最简方法是什么?
解决方案
可以通过dplyr的分组+批量处理+条件判断组合实现,核心是按ID分组后,提取每个测试列的时间序列排名,再匹配规则分类:
library(dplyr) df_result <- df %>% group_by(ID) %>% mutate( across(ends_with("_rank"), ~{ # 按时间顺序提取当前测试列的三个排名 ranks <- .[time == 1:3] case_when( # 稳定top/bottom情况 all(ranks == "top") ~ "stable(top)", all(ranks == "bottom") ~ "stable(bottom)", # 渐变序列:top -> mid -> bottom identical(ranks, c("top", "mid", "bottom")) ~ "gradual", # 突变序列:top -> bottom -> bottom identical(ranks, c("top", "bottom", "bottom")) ~ "rapid", # 其他所有情况 TRUE ~ "Other" ) }, .names = "{.col}_group") ) %>% ungroup()
代码说明
- 分组处理:
group_by(ID)保证每个ID的三个时间点数据被统一判断; - 批量匹配测试列:
across(ends_with("_rank"), ...)自动遍历所有以_rank结尾的测试列,避免重复编写规则; - 提取时间序列:
.[time == 1:3]按时间顺序取出当前测试列的三个排名值; - 规则匹配:按优先级依次判断稳定、渐变、突变情况,最后用
TRUE ~ "Other"覆盖剩余组合; - 自动命名新列:
.names = "{.col}_group"将原测试列名(如test1_rank)转换为对应的分组列名(test1_rank_group); - 取消分组:
ungroup()恢复数据框的非分组状态,方便后续操作。
运行后得到的结果与期望的df2完全一致。
内容的提问来源于stack exchange,提问作者Sid0311
相关产品推荐
相关产品推荐

