如何用dplyr按多条件分组统计数据框元素?
问题
需要用dplyr对数据框按Element和Group的连续分组进行统计,原代码通过group_by(Element, Group)生成的eleGrpCnt与期望结果不符,求正确实现方法。
数据说明
以下是目标数据格式(右侧为说明列):
| Element | Group | origOrder | eleCnt | eleGrpCnt(原代码结果) | desired_eleGrpCnt | 说明 |
|---|---|---|---|---|---|---|
| B | 0 | 1 | 1 | 1 | 1 | 第1次连续出现B+0 |
| R | 0 | 2 | 1 | 1 | 1 | 第1次连续出现R+0 |
| R | 1 | 3 | 2 | 1 | 2 | 第2次连续出现R+1 |
| R | 1 | 4 | 3 | 2 | 2 | 第2次连续出现R+1 |
| B | 0 | 5 | 2 | 2 | 1 | 第1次连续出现B+0 |
| X | 2 | 6 | 1 | 1 | 1 | 第1次连续出现X+2 |
| X | 2 | 7 | 2 | 2 | 1 | 第1次连续出现X+2 |
| X | 0 | 8 | 3 | 1 | 2 | 第2次连续出现X+0 |
| X | 0 | 9 | 4 | 2 | 2 | 第2次连续出现X+0 |
| X | -1 | 10 | 5 | 1 | 3 | 第3次连续出现X+-1 |
原代码
library(dplyr) myData6 <- data.frame( Element = c("B","R","R","R","B","X","X","X","X","X"), Group = c(0,0,1,1,0,2,2,0,0,-1) ) myData6 %>% mutate(origOrder = row_number()) %>% group_by(Element) %>% mutate(eleCnt = row_number()) %>% ungroup() %>% group_by(Element, Group) %>% mutate(eleGrpCnt = row_number())%>% ungroup()
解决方案
原代码的问题在于:group_by(Element, Group)会把所有相同Element+Group的行归为一组,不管它们在原数据中是否连续,这和「连续分组统计」的需求不符。要实现目标,需要先识别连续相同的Element+Group组合,再按Element累计这些连续组的序号。
正确代码
library(dplyr) myData6 <- data.frame( Element = c("B","R","R","R","B","X","X","X","X","X"), Group = c(0,0,1,1,0,2,2,0,0,-1) ) myData6 %>% mutate( origOrder = row_number(), # 生成Element与Group的组合标识,用于判断连续性 ele_grp_comb = paste(Element, Group, sep = "_"), # 生成连续分组ID:当前行与上一行组合不同时,计数+1 consecutive_group_id = cumsum(ele_grp_comb != lag(ele_grp_comb, default = first(ele_grp_comb))) ) %>% group_by(Element) %>% mutate( eleCnt = row_number(), # 对每个Element下的连续分组ID进行编号,得到期望的结果 desired_eleGrpCnt = dense_rank(consecutive_group_id) ) %>% ungroup() %>% # 移除中间辅助列(可选) select(-ele_grp_comb, -consecutive_group_id)
代码解释
- 生成组合标识:用
paste(Element, Group)把两列合并成一个字符串,方便判断相邻行是否属于同一连续组; - 生成连续分组ID:用
cumsum()和lag()判断当前行与上一行的组合是否变化,每次变化时计数加1,得到每个连续组的唯一ID; - 按Element编号连续组:在每个Element分组内,用
dense_rank()对连续分组ID进行排序编号,得到最终的desired_eleGrpCnt,完全匹配需求。
运行后得到的结果中,desired_eleGrpCnt列就和目标一致了。
内容的提问来源于stack exchange,提问作者Village.Idyot
相关产品推荐
相关产品推荐

