如何在R的tidyverse中用mutate_at将多列分为4个近似等规模有序组?
解决方案
要实现多分数列的近似等规模分组,核心是替换cut_number为ntile函数——ntile不依赖足够多的唯一值,而是直接按排序后的观测位置分配组,能保证每组数量尽可能均等,同时避免报错。以下是两种适配不同需求的实现方式:
方式1:强制分组(所有场景生效)
直接使用ntile对每列进行4组划分,即使存在大量重复值(如scores_2的多个0)也能生成近似等规模的组:
library(tidyverse) dat <- data.frame(Suburb = c("Werribee", "Hoppers", "Carlton", "North", "Serrano", "Upwell","Market", "Poynton", "Stawell"), scores_1 = c(0,0.0001, 230, 340, 340, 10, 3490, 5,21), scores_2 = c(12, 0,0,0,0,0,0, 45,13), scores_3 = c(4,5,6,7,8,9,10, 45, 45)) allscores <- c("scores_1", "scores_2", "scores_3") # 使用mutate across替代已软弃用的mutate_at myresult <- dat %>% mutate(across(all_of(allscores), list(risk_levels = ~ ntile(., n = 4)), .names = "{.col}_risk_levels"))
说明
ntile(x, n = 4)会将排序后的观测值划分为4组,每组数量差异不超过1:比如9条数据会分成3、2、2、2的规模。- 分组逻辑为分数越低,风险等级(组号)越小,若需要反向(分数越高等级越高),可改用
ntile(desc(x), n = 4)。
方式2:仅在有效场景分组(大量0值场景返回NA)
如果希望在唯一值不足4个的场景下不生成分组(返回NA),可以自定义函数先做判断:
assign_risk <- function(x, n = 4) { # 当唯一值数量小于分组数时返回NA,否则用ntile分组 if (n_distinct(x) < n) { rep(NA_integer_, length(x)) } else { ntile(x, n) } } myresult <- dat %>% mutate(across(all_of(allscores), list(risk_levels = assign_risk), .names = "{.col}_risk_levels"))
说明
n_distinct(x)用于统计列的唯一值数量,若小于4则返回NA向量,避免无意义的分组。- 示例中
scores_2有4个唯一值(0、12、13、45),会正常生成分组;若某列只有2个唯一值,该列的风险等级列会全为NA。
内容的提问来源于stack exchange,提问作者monkeyshines
相关产品推荐
相关产品推荐

