分组数据框中多列字符值的组内占比计算问题
按size分组计算w*列的组内列占比
原始数据
df <- data.frame( size = c(3,3,4,4,5,5), w1 = c("A","B","B","C","B","A"), w2 = c("C","A","A","C","C", "B"), w3 = c("C","A","B","C","B","B"), w4 = c(NA, NA,"C", "B", "A","B"), w5 = c(NA, NA,NA, NA, "A","C") )
需求说明
按size分组,计算每个w*列中各字符值的组内列占比(即同一size组内,某w列中某个字符出现次数占该列非NA值总数的百分比),最终输出需保留所有可能的字符值(A/B/C),且原始数据中全为NA的列,对应位置需显示NA。
原代码问题分析
- 未过滤NA值:转换长格式时保留了NA,导致统计出多余的NA行,且占比计算包含NA,结果错误
- 分组逻辑错误:计算占比时仅按
name(w列名)分组,未结合size,导致占比是全局而非组内的 - 全NA列处理不当:直接移除全NA列,无法在最终输出中保留这些列并显示NA
修正后的代码
library(tidyverse) df %>% # 按size分组,后续操作基于每个size组 group_by(size) %>% # 将w列转为长格式,同时过滤掉NA值 pivot_longer(cols = matches("w\\d+$"), names_to = "name", values_to = "value", values_drop_na = TRUE) %>% # 按size、列名、字符值统计出现次数 count(size, name, value) %>% # 按size和列名分组,计算组内占比 group_by(size, name) %>% mutate(percent = n / sum(n) * 100) %>% select(-n) %>% # 转回宽格式,缺失的字符值占比填充为0 pivot_wider(names_from = name, values_from = percent, values_fill = 0) %>% ungroup() %>% # 确保每个size组都包含A、B、C三个字符值,缺失的填充0 complete(size, value = c("A", "B", "C"), fill = list(w1=0, w2=0, w3=0, w4=0, w5=0)) %>% # 检查原始数据中该size组的对应w列是否全为NA,是则设为NA group_by(size) %>% mutate(across(matches("w\\d+$"), ~if(all(is.na(df[df$size == cur_group()$size, cur_column()]))) NA else .)) %>% ungroup() %>% # 按size和字符值排序,匹配预期输出 arrange(size, value)
输出结果
运行上述代码后,将得到与预期一致的结果:
# A tibble: 9 × 7 size value w1 w2 w3 w4 w5 <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> 1 3 A 50 50 50 NA NA 2 3 B 50 0 0 NA NA 3 3 C 0 50 50 NA NA 4 4 A 0 50 0 0 NA 5 4 B 50 0 50 50 NA 6 4 C 50 50 50 50 NA 7 5 A 0 0 0 50 50 8 5 B 100 50 100 50 0 9 5 C 0 50 0 0 50
关键步骤说明
values_drop_na = TRUE:在转换长格式时直接剔除NA值,避免干扰统计group_by(size, name):确保占比计算是同一size组内、同一w列的相对占比complete(size, value = c("A", "B", "C")):保证每个size组都包含所有可能的字符值,不会缺失行- 最后一步的
mutate(across(...)):还原原始数据中全为NA的列,对应位置显示NA,符合需求
内容的提问来源于stack exchange,提问作者Chris Ruehlemann
相关产品推荐
相关产品推荐

