在R语言中高效为数据框添加多列众数新列及类别频次统计
高效实现R数据框的频次统计与众数计算(百万级数据)
问题说明
现有如下结构的R数据框:
| id | w1 | w2 | w3 | w4 | w5 | w6 |
|---|---|---|---|---|---|---|
| 11 | light | light | light | light | light | light |
| 22 | light | light | light | light | medium | medium |
| 33 | light | light | medium | medium | medium | heavy |
| 44 | light | light | medium | NA | NA | NA |
| 55 | light | light | medium | medium | NA | NA |
| 66 | medium | medium | medium | NA | NA | NA |
需要完成以下操作:
- 统计每个
id对应的w1-w6列中light、medium、heavy的频次,生成N_light、N_medium、N_heavy列; - 基于
w1-w6列的众数生成final列(若多个值频次相同,取首次出现的那个,例如id=55时light先出现,故final为light)。
由于真实数据包含百万行,此前使用DescTools::Mode结合for循环实现,运行效率极低,需要高效解决方案。
解决方案1:使用data.table(推荐百万级数据)
data.table基于C实现,内存占用低、运算速度快,是处理大数据的首选工具:
library(data.table) # 将原数据框转换为data.table格式 dt <- as.data.table(your_data) # 1. 计算各类别频次 dt[, c("N_light", "N_medium", "N_heavy") := .( rowSums(.SD == "light", na.rm = TRUE), rowSums(.SD == "medium", na.rm = TRUE), rowSums(.SD == "heavy", na.rm = TRUE) ), .SDcols = paste0("w", 1:6)] # 2. 自定义高效众数函数(处理并列众数时取首次出现的值) get_row_mode <- function(x) { x_clean <- na.omit(x) if (length(x_clean) == 0) return(NA_character_) freq_table <- table(x_clean) max_count <- max(freq_table) # 返回第一个出现的最高频次类别 names(freq_table)[freq_table == max_count][1] } # 对每行w1-w6列应用众数函数 dt[, final := apply(.SD, 1, get_row_mode), .SDcols = paste0("w", 1:6)]
解决方案2:使用dplyr
若习惯tidyverse语法,可使用dplyr的向量化操作替代循环:
library(dplyr) library(purrr) your_data %>% mutate( # 计算各类别频次 N_light = rowSums(across(w1:w6, ~ .x == "light"), na.rm = TRUE), N_medium = rowSums(across(w1:w6, ~ .x == "medium"), na.rm = TRUE), N_heavy = rowSums(across(w1:w6, ~ .x == "heavy"), na.rm = TRUE), # 计算每行众数 final = pmap_chr(across(w1:w6), function(...) { x_clean <- na.omit(c(...)) if (length(x_clean) == 0) return(NA_character_) freq_table <- table(x_clean) max_count <- max(freq_table) names(freq_table)[freq_table == max_count][1] }) )
优化说明
- 摒弃for循环:使用
rowSums、apply/pmap等批量操作替代逐行循环,将运算效率提升数个数量级; - 轻量众数函数:自定义函数避免了
DescTools::Mode的额外封装开销,同时明确处理并列众数的逻辑; - 数据格式选择:百万级数据优先使用data.table,其内存管理和运算速度均优于dplyr。
内容的提问来源于stack exchange,提问作者New R user
相关产品推荐
相关产品推荐

