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

如何测量数据量不均的两个CDF间水平距离并匹配KS统计量

问题描述

我有两个数据集,一个含261个数据点,另一个含373个数据点,数据生成代码如下:

dataset_1 = data.frame(dataset_name = rep("dataset_1", 261), 
                       value = seq(40, 10000, length.out = 261))
dataset_2 = data.frame(dataset_name = rep("dataset_2", 373), 
                       value = seq(50, 5000, length.out = 373))

dataset <- rbind(dataset_1, dataset_2)

我已经执行了KS检验:

ks.test(dataset$value[dataset$dataset_name=="dataset_1"],
        dataset$value[dataset$dataset_name=="dataset_2"],
        alternative = c("less")) -> test_result

并绘制了ECDF曲线:

library(ggplot2)
dataset %>% 
  ggplot(aes(x= value, group = dataset_name, color = dataset_name)) +
  stat_ecdf(size =2)

两个数据集的ECDF曲线

现在我需要测量各概率点处的水平距离,比如在概率0.25时,dataset_1对应值为2500,dataset_2对应值为1250,距离为1250。但两个数据集数据点数量不同,请问如何生成展示这些距离的DataFrame?

我尝试过用线性插值把dataset_1扩展为373个数据点来验证:

interpolated_dataset_1  <- approx(dataset_1$value, n = 373)

# 创建数据框
interpolated_dataset_1_dataframe <- data.frame(dataset_name = 
              "modified_dataset_1", value = interpolated_dataset_1$y)

# 合并数据
modified_dataset <- rbind(dataset,interpolated_dataset_1_dataframe)

# KS检验
ks.test(modified_dataset$value[modified_dataset$dataset_name==
                               "modified_dataset_1"],
        modified_dataset$value[modified_dataset$dataset_name=="dataset_2"],
        alternative = c("less")) -> modified_test_result
# 绘制ECDF
library(ggplot2)
modified_dataset %>% 
  ggplot(aes(x= value, group = dataset_name, color = dataset_name)) +
  stat_ecdf(size =2)

但此时得到的D统计量和原检验接近但不完全一致,尽管结果显著。请问是否存在使用阶梯函数的更佳方法,能得到和原KS检验完全一致的统计量?


解决方案

要准确计算ECDF阶梯函数上各概率点的水平距离,不需要插值扩展数据集,直接利用ECDF的逆函数(分位数函数)即可,这样能完全匹配KS检验的阶梯逻辑,得到一致的统计量。

步骤1:定义ECDF与逆ECDF函数

ECDF函数返回给定x值对应的累积概率,逆ECDF(分位数函数)返回给定概率对应的x值,完全贴合阶梯型ECDF的特性:

# 提取两个数据集的数值向量
vals1 <- dataset_1$value
vals2 <- dataset_2$value

# 创建ECDF函数
ecdf1 <- ecdf(vals1)
ecdf2 <- ecdf(vals2)

# 创建逆ECDF(分位数)函数,type=1对应左连续阶梯特性,与KS检验逻辑完全一致
quantile1 <- function(p) quantile(vals1, p, type = 1)
quantile2 <- function(p) quantile(vals2, p, type = 1)

步骤2:生成覆盖所有阶梯的概率点

选择两个ECDF所有独特的阶梯概率点,确保覆盖所有可能的差异位置:

# 获取两个数据集的阶梯概率点
probs1 <- unique(ecdf1(vals1))
probs2 <- unique(ecdf2(vals2))
all_probs <- sort(unique(c(probs1, probs2)))  # 合并去重并排序

步骤3:计算概率点对应的距离

用逆ECDF函数计算每个概率的x值,再求水平距离:

# 构建结果DataFrame
distance_df <- data.frame(
  probability = all_probs,
  dataset_1_value = sapply(all_probs, quantile1),
  dataset_2_value = sapply(all_probs, quantile2),
  horizontal_distance = sapply(all_probs, quantile1) - sapply(all_probs, quantile2)
)

验证结果一致性

这个方法完全遵循KS检验的阶梯逻辑,计算出的最大水平距离会和原检验的D统计量完全一致:

# 检查最大距离是否等于KS检验的D统计量
max(distance_df$horizontal_distance) == test_result$statistic

可选:自定义概率点计算

如果不需要覆盖所有阶梯点,也可以指定自定义概率(如0.25、0.5等):

custom_probs <- seq(0, 1, by = 0.05)  # 0到1,步长0.05
custom_distance_df <- data.frame(
  probability = custom_probs,
  dataset_1_value = sapply(custom_probs, quantile1),
  dataset_2_value = sapply(custom_probs, quantile2),
  horizontal_distance = sapply(custom_probs, quantile1) - sapply(custom_probs, quantile2)
)

插值方法偏差的原因

线性插值是对数据点做连续插值,改变了原数据的阶梯分布特性,因此KS检验统计量会出现偏差。而直接使用type=1的分位数函数,完全匹配KS检验的左连续阶梯逻辑,能保证结果一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 17:40:35