如何在R语言中使用递归方法(如lapply/sapply)计算数据框各列重复值占比并排序结果
解决你的R语言批量计算列重复值占比问题
嘿,我来帮你搞定这个问题!你的原始代码里有个关键小错误,而且咱们得优化一下,让它能高效处理700列的大型数据框,最后还能整理成你想要的排序结果。
先说说你原始代码的问题
你写的perc_repeated函数里用了df$variables,但lapply是把数据框的每一列直接传入函数的,所以你应该直接使用函数的参数(比如叫x),而不是从原数据框里引用——这就是代码没跑通的核心原因~
优化方案:兼顾效率和简洁性
针对700列的大数据,我们要选高效的批量处理方法,同时逻辑要清晰。下面给你两种常用的方案,基础R和tidyverse风格的都有。
方案1:基础R(高效处理大型数据)
这个方案用vapply(比lapply更高效,因为提前指定了返回类型),而且计算重复次数的逻辑也做了优化:
# 先加载dplyr(如果用示例数据的话) library(dplyr) # 你的示例数据 df <- data.frame( var1 = c(1,2,3,4,5,6,7,8,9,10 ), var2 = c(1,1,2,3,4,5,6,7,9,10 ), var3 = c(1,1,1,2,3,4,5,6,7,8 ), var4 = c(2,2,1,1,2,1,1,2,1,2 ), var5 = c(1,1,1,1,1,4,5,5,6,7 ), var6 = c(4,4,4,5,5,5,5,5,5,5 ) ) # 定义计算重复值占比的函数 perc_repeated <- function(x) { # 计算重复次数:总行数 - 唯一值数量,这个比sum(table(x)-1)快很多! total_repeats <- length(x) - length(unique(x)) # 计算占比并格式化为百分比字符串 paste0(round((total_repeats / length(x)) * 100, 2), "%") } # 批量处理所有列,vapply比lapply更高效 repeated_vec <- vapply(df, perc_repeated, FUN.VALUE = character(1)) # 整理成排序后的结果数据框 df_repeated <- tibble( variable = names(repeated_vec), perc_repeated_values = repeated_vec ) %>% # 提取百分比的数值部分用于排序 mutate(perc_num = as.numeric(str_remove(perc_repeated_values, "%"))) %>% # 按占比从高到低排序 arrange(desc(perc_num)) %>% # 去掉临时的数值列 select(-perc_num) # 查看结果 df_repeated
方案2:tidyverse风格(更简洁易读)
如果你习惯用dplyr这套工具,用across函数可以更简洁地实现批量处理:
library(dplyr) library(tidyr) df_repeated <- df %>% # 对每一列计算重复值占比 summarise(across(everything(), ~{ total_repeats <- length(.) - length(unique(.)) paste0(round((total_repeats / length(.)) * 100, 2), "%") })) %>% # 把宽格式转成长格式 pivot_longer(cols = everything(), names_to = "variable", values_to = "perc_repeated_values") %>% # 提取数值用于排序 mutate(perc_num = as.numeric(str_remove(perc_repeated_values, "%"))) %>% # 降序排序 arrange(desc(perc_num)) %>% # 移除临时列 select(-perc_num)
最终结果
运行上面的代码后,你会得到完全符合预期的结果:
# A tibble: 6 × 2 variable perc_repeated_values <chr> <chr> 1 var6 80% 2 var4 80% 3 var5 50% 4 var3 20% 5 var2 20% 6 var1 0%
针对700列数据的额外优化建议
- 优先用
vapply或者across,这两个比lapply更高效,返回的结构更紧凑,减少内存占用。 - 用
length(x)-length(unique(x))计算重复次数,比sum(table(x)-1)快很多,尤其是当列中有大量不同取值时,table()函数会生成频率表,开销更大。 - 避免在函数里引用原数据框,直接使用传入的列向量,减少不必要的内存访问。
内容的提问来源于stack exchange,提问作者Rodrigo H. Ozon
相关产品推荐
相关产品推荐

