我有N个数据的数据集,我想测试其正常性。 我知道scipy.stats有一个kstest function 但是没有关于如何使用它以及如何解释结果的例子。 这里的任何人都熟悉它可以给我一些建议吗?
根据文档,使用kstest返回两个数字,即KS检验统计量D和p值。 如果p值大于显着性水平(比如说5%),那么我们就不能拒绝数据来自给定分布的假设。
当我通过从正态分布中绘制10000个样本并测试高斯度来进行测试时:
import numpy as np
from scipy.stats import kstest
mu,sigma = 0.07, 0.89
kstest(np.random.normal(mu,sigma,10000),'norm')
我得到以下输出:
(0.04957880905196102,8.9249710700788814e-22)
p值小于5%,这意味着我们可以拒绝数据正态分布的假设。但样本来自正态分布!
有人可以理解并向我解释这里的差异吗?
(正常性测试假设μ= 0且sigma = 1吗?如果是这样,我怎样才能测试我的数据是高斯分布但是有不同的mu和sigma?)
答案 0 :(得分:23)
您的数据是使用mu = 0.07和sigma = 0.89生成的。 您正在使用平均值为0且标准差为1的正态分布测试此数据。
零假设(H0
)是您的数据为样本的分布等于标准正态分布,均值为0,标准偏差为1.
小p值表示预期与概率p值一样大的D检验统计量。
换句话说,(p值~8.9e-22)H0
极不可能是真的。
这是合理的,因为平均值和标准偏差不匹配。
将您的结果与:
进行比较In [22]: import numpy as np
In [23]: import scipy.stats as stats
In [24]: stats.kstest(np.random.normal(0,1,10000),'norm')
Out[24]: (0.007038739782416259, 0.70477679457831155)
要测试你的数据是高斯的,你可以移动并重新调整它,使其正常,平均值为0,标准偏差为1:
data=np.random.normal(mu,sigma,10000)
normed_data=(data-mu)/sigma
print(stats.kstest(normed_data,'norm'))
# (0.0085805670733036798, 0.45316245879609179)
警告:(many thanks to user333700(又名scipy开发人员Josef Perktold))如果您不知道mu
和sigma
,请估算参数使p值无效:
import numpy as np
import scipy.stats as stats
mu = 0.3
sigma = 5
num_tests = 10**5
num_rejects = 0
alpha = 0.05
for i in xrange(num_tests):
data = np.random.normal(mu, sigma, 10000)
# normed_data = (data - mu) / sigma # this is okay
# 4915/100000 = 0.05 rejects at rejection level 0.05 (as expected)
normed_data = (data - data.mean()) / data.std() # this is NOT okay
# 20/100000 = 0.00 rejects at rejection level 0.05 (not expected)
D, pval = stats.kstest(normed_data, 'norm')
if pval < alpha:
num_rejects += 1
ratio = float(num_rejects) / num_tests
print('{}/{} = {:.2f} rejects at rejection level {}'.format(
num_rejects, num_tests, ratio, alpha))
打印
20/100000 = 0.00 rejects at rejection level 0.05 (not expected)
表明stats.kstest
可能不会拒绝预期的空假设数
如果样本使用样本的均值和标准差进行标准化
normed_data = (data - data.mean()) / data.std() # this is NOT okay
答案 1 :(得分:10)
unutbu答案的最新消息:
对于仅依赖于位置和比例但没有形状参数的分布,几个拟合优度检验统计量的分布与位置和比例值无关。分发是非标准的,但是,它可以制表并与基础分布的任何位置和比例一起使用。
具有估计位置和尺度的正态分布的Kolmogorov-Smirnov检验也称为Lilliefors test。
现在可以在statsmodels中使用,具有相关决策范围的近似p值。
>>> import numpy as np
>>> mu,sigma = 0.07, 0.89
>>> x = np.random.normal(mu, sigma, 10000)
>>> import statsmodels.api as sm
>>> sm.stats.lilliefors(x)
(0.0055267411213540951, 0.66190841161592895)
大多数蒙特卡罗研究表明,Anderson-Darling测试比Kolmogorov-Smirnov测试更强大。它在具有临界值的scipy.stats中可用,在具有近似p值的statsmodel中可用:
>>> sm.stats.normal_ad(x)
(0.23016468240712129, 0.80657628536145665)
这两项测试都没有拒绝Null假设,即样本是正态分布的。 虽然问题中的最新部分拒绝了Null假设,即样本标准正态分布。
答案 2 :(得分:3)
您可能还需要考虑使用Shapiro-Wilk测试,该测试&#34;测试数据来自正态分布的原假设。&#34;它也在scipy
中实现:
http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.shapiro.html
您需要将数据直接传递到函数中。
import scipy
W, p = scipy.stats.shapiro(dataset)
print("Shapiro-Wilk test statistic, W:", W, "\n", "p-value:", p)
返回类似的内容:
Shapiro-Wilk test statistic, W: 0.7761164903640747
p-value: 6.317247641091492e-37
p <&lt;&lt; 0.01(或0.05,如果您愿意 - 它并不重要),我们有充分的理由拒绝这些数据来自正态分布的零假设。
答案 3 :(得分:1)
作为@unutbu答案的补充,您还可以在kstest中提供测试分布的分布参数。假设我们从变量中得到了一些样本(并将它们命名为datax),我们想检查这些样本是否可能不是来自对数正态,均匀或正常。请注意,对于scipy stats,每个分布的输入参数的方式略有不同。现在,由于kstest中的“args”(元组或序列),可以为您要测试的scipy.stats发行版提供参数。
:)我还添加了使用双样本测试的选项,以防你想要这样做:
import numpy as np
from math import sqrt
from scipy.stats import kstest, ks_2samp, lognorm
import scipy.stats
def KSSeveralDists(data,dists_and_args,samplesFromDists=100,twosampleKS=True):
returnable={}
for dist in dists_and_args:
try:
if twosampleKS:
try:
loc=dists_and_args[dist][0]
scale=dists_and_args[dist][1]
expression='scipy.stats.'+dist+'.rvs(loc=loc,scale=scale,size=samplesFromDists)'
sampledDist=eval(expression)
except:
sc=dists_and_args[dist][0]
loc=dists_and_args[dist][1]
scale=dists_and_args[dist][2]
expression='scipy.stats.'+dist+'.rvs(sc,loc=loc,scale=scale,size=samplesFromDists)'
sampledDist=eval(expression)
D,p=ks_2samp(data,sampledDist)
else:
D,p=kstest(data,dist,N=samplesFromDists,args=dists_and_args[dist])
except:
continue
returnable[dist]={'KS':D,'p-value':p}
return returnable
a=lambda m,std: m-std*sqrt(12.)/2.
b=lambda m,std: m+std*sqrt(12.)/2.
sz=2000
sc=0.5 #shape
datax=lognorm.rvs(sc,loc=0.,scale=1.,size=sz)
normalargs=(datax.mean(),datax.std())
#suppose these are the parameters you wanted to pass for each distribution
dists_and_args={'norm':normalargs,
'uniform':(a(*normalargs),b(*normalargs)),
'lognorm':[0.5,0.,1.]
}
print "two sample KS:"
print KSSeveralDists(datax,dists_and_args,samplesFromDists=sz,twosampleKS=True)
print "one sample KS:"
print KSSeveralDists(datax,dists_and_args,samplesFromDists=sz,twosampleKS=False)
给出了类似的输出:
两个样本KS: {'lognorm':{'KS':0.023499999999999965,'p-value':0.63384188886455217},'norm':{'KS':0.10600000000000004,'p-value':2.918766666723155e-10},'uniform':{' KS':0.15300000000000002,'p-value':6.443660021191129e-21}}
一个样本KS: {'lognorm':{'KS':0.01763415915126032,'p-value':0.56275820961065193},'norm':{'KS':0.10792612430093562,'p-value':0.0},'uniform':{'KS': 0.14910036159697559,'p-value':0.0}}
注意:对于scipy.stats均匀分布,a和b被视为a = loc而b = loc + scale(参见documentation)。