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

如何生成3D百分位数?能否从数据云质心构建递增范围?

问题:基于数据质心构建3D单调递增百分位数范围

数据生成代码

set.seed(123)
n <- 10000
age <- rnorm(n, 40, 10)
weight <- rnorm(n, 70, 15)
height <- rnorm(n, 170, 10)

需求

生成3D百分位数,例如:X%的样本处于(Age1-Age2, Weight1-Weight2, Height1-Height2)区间内,(X+Y)%的样本处于(Age1-Age3, Weight1-Weight3, Height1-Height3)区间内等,且范围需单调递增。

现有尝试

通过单变量分位数划分箱体,代码如下:

age_cuts <- quantile(age, probs = seq(0, 1, 0.1))
weight_cuts <- quantile(weight, probs = seq(0, 1, 0.1))
height_cuts <- quantile(height, probs = seq(0, 1, 0.1))

results <- data.frame()

for(i in 2:length(age_cuts)) {
    age_range <- c(age_cuts[1], age_cuts[i])
    weight_range <- c(weight_cuts[1], weight_cuts[i])
    height_range <- c(height_cuts[1], height_cuts[i])
    
    in_box <- age >= age_range[1] & age <= age_range[2] &
        weight >= weight_range[1] & weight <= weight_range[2] &
        height >= height_range[1] & height <= height_range[2]
    
    percent <- sum(in_box) / n * 100
    
    results <- rbind(results, data.frame(
        decile = (i-1) * 10,
        age_min = age_range[1],
        age_max = age_range[2],
        weight_min = weight_range[1],
        weight_max = weight_range[2],
        height_min = height_range[1],
        height_max = height_range[2],
        percent_contained = percent,
        n_points = sum(in_box)
    ))
}

运行结果

decile  age_min  age_max weight_min weight_max height_min height_max percent_contained n_points
     10 1.546798 27.20561     17.669   50.64000   134.5412   157.0580              0.06        6
     20 1.546798 31.60029     17.669   57.34884   134.5412   161.4875              0.75       75
     30 1.546798 34.81272     17.669   62.03452   134.5412   164.6067              2.72      272
     40 1.546798 37.51687     17.669   65.96050   134.5412   167.2295              6.56      656
     50 1.546798 39.88911     17.669   69.73178   134.5412   169.8810             12.65     1265
     60 1.546798 42.47684     17.669   73.59989   134.5412   172.4757             22.12     2212
     70 1.546798 45.18560     17.669   77.53439   134.5412   175.3048             34.58     3458
     80 1.546798 48.42140     17.669   82.53608   134.5412   178.4548             51.38     5138
     90 1.546798 52.62804     17.669   89.25561   134.5412   182.8159             72.73     7273
    100 1.546798 78.47768     17.669  126.38053   134.5412   213.2282            100.00    10000

示意图

疑问

能否从数据云的质心起始构建百分位数范围?这样是否能保证单调递增的范围覆盖的样本占比持续增大?


回答

完全可以从数据质心出发构建这类3D百分位数范围,而且只要方法得当,绝对能保证覆盖的样本占比单调递增。

核心思路

从质心(也就是三个变量的均值点:(mean(age), mean(weight), mean(height)))向外扩展,本质是按样本到质心的距离排序,然后按分位数截取距离阈值,对应生成包含质心的嵌套区间(或超球体/超椭球)。因为每次扩展都是把更远的样本纳入,所以覆盖比例必然是逐步增加的,天然满足单调递增的要求。

具体实现步骤

  • 计算质心:先算出三个变量的均值,作为中心原点。
  • 标准化变量(可选但推荐):因为年龄、体重、身高的量纲不同,直接计算欧氏距离会被方差大的变量主导,所以先标准化每个变量:
    age_std <- scale(age)
    weight_std <- scale(weight)
    height_std <- scale(height)
    
  • 计算每个样本到质心的距离:用标准化后的数据计算欧氏距离:
    distances <- sqrt(age_std^2 + weight_std^2 + height_std^2)
    
  • 按距离分位数划分阈值:生成距离的分位数,作为扩展的边界:
    dist_cuts <- quantile(distances, probs = seq(0, 1, 0.1))
    
  • 映射回原始变量的区间:对每个距离阈值,找到所有距离小于等于该阈值的样本,然后提取这些样本在原始变量上的最小和最大值,得到对应的3D区间:
    results_centroid <- data.frame()
    centroid_age <- mean(age)
    centroid_weight <- mean(weight)
    centroid_height <- mean(height)
    
    for(i in 1:length(dist_cuts)) {
        if(i == 1) next  # 跳过0分位数,对应质心单点
        current_dist <- dist_cuts[i]
        in_range <- distances <= current_dist
        
        # 提取原始变量的区间
        age_min <- min(age[in_range])
        age_max <- max(age[in_range])
        weight_min <- min(weight[in_range])
        weight_max <- max(weight[in_range])
        height_min <- min(height[in_range])
        height_max <- max(height[in_range])
        
        percent <- sum(in_range)/n *100
        
        results_centroid <- rbind(results_centroid, data.frame(
            decile = (i-1)*10,
            centroid_age = centroid_age,
            centroid_weight = centroid_weight,
            centroid_height = centroid_height,
            age_min = age_min,
            age_max = age_max,
            weight_min = weight_min,
            weight_max = weight_max,
            height_min = height_min,
            height_max = height_max,
            percent_contained = percent,
            n_points = sum(in_range)
        ))
    }
    

为什么能保证单调递增?

因为每次循环的距离阈值是逐步增大的,dist_cuts是从0到最大距离的分位数,所以in_range的样本集合是嵌套包含的:第k个分位数的样本集合完全包含第k-1个分位数的样本集合。因此覆盖的样本占比必然是严格递增的,不会出现波动。

和现有方法的区别

之前的方法是从每个变量的最小值开始扩展,相当于从数据的“角落”往外扩,样本覆盖比例的增长非线性且可能不符合直觉;而从质心扩展是从数据最密集的区域向外扩散,更符合“百分位数范围”的直观理解——比如10%的样本是离中心最近的10%,90%是包含所有离中心较近的90%样本。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 17:37:08