如何在Python中实现KS测试

时间:2019-05-13 20:22:30

标签: python scipy statistics hypothesis-test kolmogorov-smirnov

scipy.stats.kstest(rvs, cdf, N)可以对数据集rvs执行KS检验。它测试数据集是否遵循概率分布,该分布的cdf在此方法的参数中指定。

现在考虑一个N=4800个样本的数据集。我已经对此数据执行了KDE,因此,有了一个估计的PDF。该PDF看起来非常像双峰分布。当绘制估计的PDF并为其拟合双峰分布的curve_fit时,这两个图几乎相同。拟合双峰分布的参数为(scale1,mean1,stdv1,scale2,mean2,stdv2): [0.6 0.036 0.52, 0.23 1.25 0.4]

如何应用scipy.stats.kstest测试我估计的PDF是否为双峰分布? 作为我的零假设,我声明估计的PDF等于以下PDF:

hypoDist = 0.6*norm(loc=0, scale=0.2).pdf(x_grid) + 0.3*norm(loc=1, scale=0.2).pdf(x_grid)
hypoCdf = np.cumsum(hypoDist)/len(x_grid)

x_grid只是一个包含x值的向量,我在该向量上评估估算的PDF。因此,pdf的每个条目都有一个对应的值x_grid。我对hypoCdf的计算可能不正确。也许我应该除以len(x_grid)而不是除以np.sum(hypoDist)吗?

挑战:cdf的{​​{1}}参数不能指定为双峰。我也不能将其指定为kstest

如果我想测试我的数据集是否是高斯分布的,我会写:

hypoDist

KS_result = kstest(measurementError, norm(loc=mean(pdf), scale=np.std(pdf)).cdf) print(KS_result) 是我执行过KDE的数据集。返回: measurementError 对我来说,pvalue为0.0有点烦人

1 个答案:

答案 0 :(得分:1)

cdf的{​​{1}}参数可以是一个可调用,它实现要测试数据的分布的累积分布函数。要使用它,您必须实现双峰分布的CDF。您希望分布是两个正态分布的混合。您可以通过计算构成混合的两个正态分布的CDF的加权总和来实现此分布的CDF。

这是一个脚本,显示如何执行此操作。为了演示如何使用kstest,该脚本运行了kstest两次。首先,它使用的样本不是分布中的不是。正如预期的那样,kstest为此第一个样本计算了一个非常小的p值。然后生成从混合物中提取的样品。对于此样本,p值不小。

kstest

典型输出(每次运行脚本时数字都会不同):

import numpy as np
from scipy import stats


def bimodal_cdf(x, weight1, mean1, stdv1, mean2, stdv2):
    """
    CDF of a mixture of two normal distributions.
    """
    return (weight1*stats.norm.cdf(x, mean1, stdv1) +
            (1 - weight1)*stats.norm.cdf(x, mean2, stdv2))


# We only need weight1, since weight2 = 1 - weight1.
weight1 = 0.6
mean1 = 0.036
stdv1 = 0.52
mean2 = 1.25
stdv2 = 0.4

n = 200

# Create a sample from a regular normal distribution that has parameters
# similar to the bimodal distribution.
sample1 = stats.norm.rvs(0.5*(mean1 + mean2), 0.5, size=n)

# The result of kstest should show that sample1 is not from the bimodal
# distribution (i.e. the p-value should be very small).
stat1, pvalue1 = stats.kstest(sample1, cdf=bimodal_cdf,
                              args=(weight1, mean1, stdv2, mean2, stdv2))
print("sample1 p-value =", pvalue1)

# Create a sample from the bimodal distribution.  This sample is the
# concatenation of samples from the two normal distributions that make
# up the bimodal distribution.  The number of samples to take from the
# first distributions is determined by a binomial distribution of n
# samples with probability weight1.
n1 = np.random.binomial(n, p=weight1)
sample2 = np.concatenate((stats.norm.rvs(mean1, stdv1, size=n1),
                         (stats.norm.rvs(mean2, stdv2, size=n - n1))))

# Most of time, the p-value returned by kstest with sample2 will not
# be small.  We expect the value to be uniformly distributed in the interval
# [0, 1], so in general it will not be very small.
stat2, pvalue2 = stats.kstest(sample2, cdf=bimodal_cdf,
                              args=(weight1, mean1, stdv1, mean2, stdv2))
print("sample2 p-value =", pvalue2)

对于您的问题,您可能会发现此测试无法正常运行。您有4800个样本,但是在代码中有一些参数,它们的数值只有一个或两个有效数字。除非您有充分的理由相信您的样本是从具有恰好个参数的分布中提取的,否则sample1 p-value = 2.8395166853884146e-11 sample2 p-value = 0.3289374831186403 可能会返回非常个小p-值。