如何为 R 中的给定向量选择最合适的分布?

机器算法验证 r 分布 拟合优度
2022-03-24 14:19:29

在为变量创建蒙特卡罗模拟模型时,关键步骤是选择最适合变量概率密度的分布。

我通常通过查看密度图并确定最适合密度形状的分布来做到这一点。对于(一个非常蹩脚的)例子,这个......

x <- rnorm(1000)
plot(density(x))

…似乎是一个正态分布(但只是因为它是来自正态分布的随机样本)。

然而,在处理现实世界的数据时,很难知道 17 个内置分布中的哪一个最能代表数据的形状。

例如,这个数据……

data <- c(6.515, 0.243, 0.725, 2.276, 1.456, 4.047, 0.766, 0.29, 2.368, 
0.543, 2.223, 0.488, 0.47, 3.511, 0.544, 4.191, 0.414, 0.704, 
4.917, 0.434, 0.773, 0.477, 3.257, 0.415, 1.921, 0.278, 3.159, 
4.193, 0.132, 1.109, 1.538, 4.088, 0.468, 0.047, 2.204, 3.765, 
0.168, 2.231, 0.164, 0.371, 2.33, 4.458, 0.046, 1.195, 1.714, 
1.046, 1.915, 2.66, 5.409, 0.466)

plot(density(data))

阴谋

......似乎最好用卡方分布建模,但它也可能是伽马分布。

我发现适合最佳模型类型的唯一方法是覆盖一堆不同的可能分布,直到我看到一个在视觉上匹配(或接近)的分布。但肯定有一种更数字化、更正式的方式来做到这一点,对吧?

是否有一种系统的、非视觉的(和自动化的)方法来找到给定变量的最佳分布?某些 R 函数中是否有一个函数通过不同的分布来检查它们的拟合优度,或者那是非常低效的?

2个回答

在决定分配时,科学比测试更重要。想想是什么导致了数据,哪些值是可能的、可能的和有意义的。正式测试可以发现明显的差异,但通常不能排除相似的分布(并注意卡方分布是伽马分布的特例)。看看这个快速模拟(并尝试使用其他值):

> mean(replicate(1000, ks.test( rt(5000, df=20), pnorm )$p.value)<0.05)
[1] 0.111

即使样本量为 5000 ,ks.test也只能找到 20 df 的 t 分布与 11% 的标准正态分布之间的差异。

如果您真的想测试发行版,那么我建议您使用包vis.test中的函数TeachingDemos它不是精确拟合的严格测试,而是显示原始数据的图与来自候选分布的类似图混合,并要求您(或其他查看者)挑选出原始数据的图。如果您无法在视觉上区分您的数据和模拟数据,那么候选分布可能是一个合理的起点(但这并不排除其他可能的分布,请考虑哪些分布在科学上最有意义)。

另一种方法是从原始数据的密度估计中生成新数据。R的logspline包具有估计密度的功能,然后从该估计中生成随机数据。或者,从核密度估计生成数据意味着从数据中选择一个点,然后从以该点为中心的核生成一个随机值。这可以像从替换数据中选择一个随机样本一样简单,然后向这些值添加小的正态偏差。

没有理由“官方”发行版之一适合您的数据。用于检查分布拟合的最相关的统计检验是 Kolmogorov-Smirnov 检验。例如,

> x=rnorm(133) 
> ks.test(x,"pnorm",mean(x),sd(x))

        One-sample Kolmogorov-Smirnov test

data:  x 
D = 0.0388, p-value = 0.9882
alternative hypothesis: two-sided

(需要注意的是 p 值不考虑参数估计)。

编辑:为了找到合适的 p 值,可以使用蒙特卡洛实验,即从假设的分布中生成样本的样本,并为每个样本推导出 ks.test 距离。然后可以使用这个 ks.distances 样本来找到经验 p 值:x

ksdist=rep(0,10^2)
for (t in 1:10^2){
  x=rnorm(length(x0),mean(x0),sd(x0))
  ksdist[t]=ks.test(x,"pnorm",mean(x),sd(x))$stat 
  }
empvalue=sum(ksdist>ks.test(x0,"pnorm",mean(x0),sd(x0))$stat)/10^2

例如,

> x0=rt(123,df=4)
> empvalue
[1] 0.02
> ks.test(x0,"pnorm",mean(x0),sd(x0))$p
[1] 0.2996538

> x0=rnorm(321)
> empvalue
[1] 0.1
> ks.test(x0,"pnorm",mean(x0),sd(x0))$p
[1] 0.568052

显示模拟如何纠正不正确的 p 值。(这个练习通常是我探索性统计期末考试的一部分。)