You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言分组分位数计算:Method 2正确性验证及修正问询

分组分位数分组实现验证与优化

数据集构建

set.seed(123)
library(dplyr)

var1 = rnorm(10000, 100,100)
var2 = rnorm(10000, 100,100)
var3 = rnorm(10000, 100,100)
var4 = rnorm(10000, 100,100)
var5 <- factor(sample(c("Yes", "No"), 1000, replace=TRUE, prob=c(0.4, 0.6)))
var6 <- factor(sample(c("Yes", "No"), 1000, replace=TRUE, prob=c(0.4, 0.6)))

my_data = data.frame( var1, var2, var3, var4, var5, var6)

需求目标

  • 按分类变量var5和var6分组
  • 对var3划分10个分位组,生成变量class3
  • 对var4按20%间隔划分5个分位组,生成变量class4

当前两种手动实现方法

Method 1:生成较多NA值

library(dplyr)
final = my_data %>% group_by(var5, var6) %>%
  mutate(class3 = case_when(ntile(var3, 10) == 1 ~ paste0(round(min(var3), 2), " to ", round(quantile(var3, 0.1), 2), " decile 1"),
                            ntile(var3, 10) == 2 ~ paste0(round(quantile(var3, 0.1), 2), " to ", round(quantile(var3, 0.2), 2), " decile 2"),
                            ntile(var3, 10) == 3 ~ paste0(round(quantile(var3, 0.2), 2), " to ", round(quantile(var3, 0.3), 2), " decile 3"),
                            ntile(var3, 10) == 4 ~ paste0(round(quantile(var3, 0.3), 2), " to ", round(quantile(var3, 0.4), 2), " decile 4"),
                            ntile(var3, 10) == 5 ~ paste0(round(quantile(var3, 0.4), 2), " to ", round(quantile(var3, 0.5), 2), " decile 5"),
                            ntile(var3, 10) == 6 ~ paste0(round(quantile(var3, 0.5), 2), " to ", round(quantile(var3, 0.6), 2), " decile 6"),
                            ntile(var3, 10) == 7 ~ paste0(round(quantile(var3, 0.6), 2), " to ", round(quantile(var3, 0.7), 2), " decile 7"),
                            ntile(var3, 10) == 8 ~ paste0(round(quantile(var3, 0.7), 2), " to ", round(quantile(var3, 0.8), 2), " decile 8"),
                            ntile(var3, 10) == 9 ~ paste0(round(quantile(var3, 0.8), 2), " to ", round(quantile(var3, 0.9), 2), " decile 9"),
                            ntile(var3, 10) == 10 ~ paste0(round(quantile(var3, 0.9), 2), " to ", round(max(var3), 2), " decile 10"))) %>%

  mutate(class4 = case_when(ntile(var4, 20) == 1 ~ paste0(round(min(var4), 2), " to ", round(quantile(var4, 0.1), 2), " pcile 1"),
                            ntile(var4, 20) == 2 ~ paste0(round(quantile(var4, 0.1), 2), " to ", round(quantile(var4, 0.2), 2), " pcile 2"),
                            ntile(var4, 20) == 3 ~ paste0(round(quantile(var4, 0.2), 2), " to ", round(quantile(var4, 0.3), 2), " pcile 3"),
                            ntile(var4, 20) == 4 ~ paste0(round(quantile(var4, 0.3), 2), " to ", round(quantile(var4, 0.4), 2), " pcile 4"),
                            ntile(var4, 20) == 5 ~ paste0(round(quantile(var4, 0.4), 2), " to ", round(quantile(var4, 0.5), 2), " pcile 5")))

Method 2:生成较少NA值

final = my_data %>% group_by(var5, var6) %>%  mutate(class3 = paste0(cut(var3, breaks = c(-Inf, quantile(var3, c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9)), Inf), 
                                                                 labels = c("ptile 1", "ptile 2", "ptile 3", "ptile 4", "ptile 5", "ptile 6", "ptile 7", "ptile 8", "ptile 9", "ptile 10")),
                                                             " (", round(min(var3), 2), " to ", round(max(var3), 2), ")")) %>% 
    mutate(class4 = paste0(cut(var4, breaks = c(-Inf, quantile(var4, c(0.2, 0.4, 0.6, 0.8)), Inf), 
                               labels = c("ptile 1", "ptile 2", "ptile 3", "ptile 4", "ptile 5")),
                           " (", round(min(var4), 2), " to ", round(max(var4), 2), ")"))

Method 2的问题分析与修正方案

存在的问题

Method 2的分组逻辑方向正确,但有两个明显缺陷:

  1. 区间标签信息错误:当前class3和class4后拼接的是分组整体的最小/最大值,而非对应分位组的实际区间范围,无法体现分位的真实边界。
  2. 小样本分组下的分位数稳定性问题:quantile()默认的type=7计算方式,在分组样本量较小时可能生成不稳定的分位数,甚至出现NA,导致cut()输出NA值。

修正后的实现方案

以下方案解决上述问题,同时简化逻辑、保证标签准确性:

library(dplyr)
library(scales) # 用于统一数值格式化

final <- my_data %>%
  group_by(var5, var6) %>%
  # 处理var3的10分位分组
  mutate(
    # 用type=1计算分位数,避免小样本下的NA与不稳定问题
    q3 = quantile(var3, probs = seq(0, 1, 0.1), type = 1),
    # 执行分组,include.lowest确保最小值被归入第一组
    class3_raw = cut(var3, breaks = q3, include.lowest = TRUE, labels = paste0("decile ", 1:10)),
    # 自动提取对应分位的区间并格式化标签
    class3 = paste0(class3_raw, " (", 
                   number(q3[as.integer(class3_raw)], accuracy = 0.01), 
                   " to ", 
                   number(q3[as.integer(class3_raw)+1], accuracy = 0.01), 
                   ")")
  ) %>%
  # 处理var4的5分位分组(20%间隔)
  mutate(
    q4 = quantile(var4, probs = seq(0, 1, 0.2), type = 1),
    class4_raw = cut(var4, breaks = q4, include.lowest = TRUE, labels = paste0("pcile ", 1:5)),
    class4 = paste0(class4_raw, " (", 
                   number(q4[as.integer(class4_raw)], accuracy = 0.01), 
                   " to ", 
                   number(q4[as.integer(class4_raw)+1], accuracy = 0.01), 
                   ")")
  ) %>%
  # 移除临时变量
  select(-q3, -class3_raw, -q4, -class4_raw) %>%
  ungroup()

关键优化点

  • 采用type=1的分位数计算逻辑,确保小样本分组下的断点稳定无NA。
  • include.lowest=TRUE避免最小值被遗漏在分组之外。
  • 自动匹配分位组对应的区间断点,生成准确的标签内容。
  • 使用scales::number()统一数值格式,保证输出美观一致。

另外,Method 1的核心问题在于ntile()强制均分的逻辑与quantile()的分位数逻辑不匹配,加上冗余的case_when写法容易出错,不推荐使用。


内容的提问来源于stack exchange,提问作者stats_noob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 06:55:55