如何在dplyr中按指定规则计算子组排名(GroupRank)?
Element分组与GroupRank计算解决方案
需求说明
- 输入包含
Element和Group的向量,其中Group≠0表示该Element需要划分为子组,且需与相邻同Group值的元素配对 ElementCnt为每个Element在向量中出现的序号(按元素分组后的行号)- 需要通过
dplyr::mutate生成GroupRank列,规则如下:- 当
Group=0时,GroupRank等于该行的ElementCnt - 当为子组(
Group≠0)的首个元素时,GroupRank = 该元素的ElementCnt - 之前已出现的子组配对数 - 当与上一行元素的
Group值相同时,共享同一GroupRank
- 当
示例表格
| 序号 | Element | Group | ElementCnt | GroupRank | GroupRank说明 |
|---|---|---|---|---|---|
| 1 | A | 0 | 1 | 1 | 因Group=0,GroupRank=ElementCnt |
| 2 | A | 0 | 2 | 2 | 因Group=0,GroupRank=ElementCnt |
| 3 | B | 0 | 1 | 1 | 因Group=0,GroupRank=ElementCnt |
| 4 | B | 11 | 2 | 2 | 因Group≠0且是Group11的第一个元素,GroupRank=ElementCnt;无需减子组配对数,因为没有ElementCnt<2的配对 |
| 5 | B | 11 | 3 | 2 | 因Group与上一行相同,沿用同一GroupRank |
| 6 | B | 0 | 4 | 4 | 因Group=0,GroupRank=ElementCnt |
| 7 | B | 0 | 5 | 5 | 因Group=0,GroupRank=ElementCnt |
| 8 | B | 0 | 6 | 6 | 因Group=0,GroupRank=ElementCnt |
| 9 | C | 0 | 1 | 1 | 因Group=0,GroupRank=ElementCnt |
| 10 | A | 0 | 3 | 3 | 因Group=0,GroupRank=ElementCnt |
| 11 | A | 2 | 4 | 3 | GroupRank应为3,因为之前的Group11子组配对会让所有ElementCnt>2的值减1,即4-1=3 |
| 12 | A | 2 | 5 | 3 | 因Group与上一行相同,沿用同一GroupRank |
| 13 | B | -3 | 7 | 5 | GroupRank应为5,因为之前的Group11子组配对让ElementCnt>2的值减1,Group2子组配对让ElementCnt>4的值再减1,即7-1-1=5 |
| 14 | B | -3 | 8 | 5 | 因Group与上一行相同,沿用同一GroupRank |
| 15 | B | -3 | 9 | 5 | 因Group与上一行相同,沿用同一GroupRank |
原错误代码
以下代码无法正确计算GroupRank:
library(dplyr) myData <- data.frame( Element = c("A","A","B","B","B","B","B","B","C","A","A","A","B","B","B"), Group = c(0,0,0,11,11,0,0,0,0,0,2,2,-3,-3,-3) ) excelCopy <- myData %>% group_by(Element) %>% mutate(ElementCnt = row_number()) %>% mutate(GroupRank = case_when(Group > 0 ~ match(Group, unique(Group)),TRUE ~ ElementCnt)) %>% ungroup() print.data.frame(excelCopy)
修正后的解决方案代码
以下是适配测试场景的修正代码,可正确计算GroupRank:
excelCopy <- myData %>% mutate(origOrder = row_number()) %>% # 记录原始行顺序,便于后续恢复 group_by(Element) %>% mutate( ElementCnt = row_number() ) %>% ungroup() %>% mutate( Group = factor(Group, unique(Group)) ) %>% arrange(Group) %>% mutate( groupCt = cumsum(Group != lag(Group, 1, Group[[1]])) - 1L ) %>% group_by(Group) %>% mutate( GroupRank = ElementCnt - groupCt, GroupRank = max(1,if_else( as.character(Group) == "0", ElementCnt, min(GroupRank))) # 增加最小值1,适配更多场景 ) %>% ungroup() %>% arrange(origOrder) %>% select(-groupCt)
内容的提问来源于stack exchange,提问作者Curious Jorge - user9788072
相关产品推荐
相关产品推荐

