R语言按多key分组求数值列average、分类列mode的实现问题
解决方案
首先R基础环境没有内置众数计算函数,需要先自定义众数处理函数:
# 自定义众数函数,默认返回出现频次最高的第一个值,可按需调整多众数、NA处理逻辑 get_mode <- function(x) { uniq_x <- unique(na.omit(x)) uniq_x[which.max(tabulate(match(x, uniq_x)))] }
基于原有plyr逻辑的修改方案
调整ddply内的处理逻辑,同时计算数值列均值与分类列众数即可:
library(plyr) groupColumns = c("SO","LI") # 注意与实际数据的列名大小写保持一致 # 提取排除分组key后的数值列、分类列 num_cols <- setdiff(colnames(Planning_DF)[sapply(Planning_DF, is.numeric)], groupColumns) cat_cols <- setdiff(colnames(Planning_DF)[sapply(Planning_DF, function(col) is.factor(col) | is.character(col))], groupColumns) res = ddply(Planning_DF, groupColumns, function(x) { # 数值列计算均值 num_res <- as.list(colMeans(x[num_cols], na.rm = TRUE)) # 分类列计算众数 cat_res <- lapply(x[cat_cols], get_mode) # 合并两类结果返回 c(num_res, cat_res) }) head(res)
更简洁的dplyr实现方案
如果可以使用dplyr包,代码可读性和执行效率更高:
library(dplyr) res <- Planning_DF %>% group_by(SO, LI) %>% summarise( # 非分组的数值列取均值 across(where(is.numeric) & !c(SO, LI), mean, na.rm = TRUE), # 非分组的字符/因子类列取众数 across(where(~is.character(.x) | is.factor(.x)) & !c(SO, LI), get_mode), .groups = "drop" ) head(res)
注意事项
- 若分组后某分类列存在多个相同频次的众数,上述自定义函数默认返回第一个出现的众数,若需要返回所有众数可调整
get_mode的逻辑 - 分组列名的大小写必须和实际数据集完全匹配,避免出现列匹配失败的问题
内容的提问来源于stack exchange,提问作者user3789200
相关产品推荐
相关产品推荐

