1 检查是否对称
一般来说,统计量较小的时候使用点图,n较大的时候使用直方图,可以揭示一元分布的一个尾部比另一个长的多的情况.
例子
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats
from matplotlib import style
mu, sigma = 0, 0.
s = np.random.normal(mu, sigma, 1000)
f, ax = plt.subplots(figsize=(10, 7))
plt.scatter(x=range(len(s)), y=s, c='r')
plt.xlim(0,500)
plt.show()
sns.distplot(s)
是不是很对称啊
我们熟悉一下更多的正态分布样图
style.use('fivethirtyeight')
mu_params = [-1, 0, 1]
sd_params = [0.5, 1, 1.5]
x = np.linspace(-7, 7, 100)
f, ax = plt.subplots(len(mu_params), len(sd_params), sharex=True, sharey=True, figsize=(12,8))
for i in range(3):
for j in range(3):
mu = mu_params[i]
sd = sd_params[j]
y = stats.norm(mu, sd).pdf(x)
ax[i, j].plot(x, y)
ax[i, j].plot(0,0, label='mu={:3.2f}\nsigma={:3.2f}'.format(mu,sd), alpha=0)
ax[i, j].legend(fontsize=10)
ax[2,1].set_xlabel('x', fontsize=16)
ax[1,0].set_ylabel('pdf(x)', fontsize=16)
plt.suptitle('Gaussian PDF', fontsize=16)
plt.tight_layout()
plt.show()
2 区间检查
一元正态分布属于区间(μ-σ,μ+σ)内的取值概率为0.683,
属于区间(μ-2σ,μ+2σ)内的取值概率为0.954
在(μ-3σ,μ+3σ)内的取值概率为0.997
sigma = 2
list(map(lambda x: stats.norm.cdf(x*sigma,loc=0,scale=sigma) - stats.norm.cdf(-x*sigma,loc=0,scale=sigma), range(1, 6)))
[0.6826894921370859,
0.9544997361036416,
0.9973002039367398,
0.9999366575163338,
0.9999994266968562]
3 QQ图与PP图
QQ图(Quantile Quantile Plot)有两个作用,1检查一组数据是否服从同一分布,2检查两个分布是否服从同一分布
QQ图原理是比较两组数据的累计分布函数来判断两组数据是否是服从同一分布,所以第一步我们应该做两组数据的累计分布。首先,作为对比我们看一下标准正太分布的累计分布图
x = np.linspace(-5, 5, 100)
y = stats.norm.cdf(x, 0, 1)
plt.plot(x, y)
然后,绘制目标数据(这里使用随机生成的数据集)的累计分布函数图
x = np.random.normal(0, 1, 100)
sorted_ = np.sort(x)
yvals = np.arange(len(sorted_))/float(len(sorted_))
plt.plot(sorted_, yvals)
直观上对比,目标累计分布函数图和标准正太累计分布函数图差异不大,事实是不是这样呢?最后我们就可以做pp图做对比。
x_label = stats.norm.ppf(yvals) #对目标累计分布函数值求标准正太分布累计分布函数的逆
plt.scatter(x_label, sorted_)
stats.probplot(x, dist="norm", plot=plt)
plt.show()
下面做个QQ图进行比较
import statsmodels.api as sm
nsample = 100
plt.figure(figsize=(10, 8))
sm.qqplot(stats.t.rvs(25, size=nsample), line='45')
除了正态分布,我们还可以检测t分布(自动度较小)
nsample = 100
plt.figure(figsize=(10, 8))
x = stats.t.rvs(3, size=nsample)
res = stats.probplot(x, plot=plt)
检测t分布(自动度较大)
nsample = 100
plt.figure(figsize=(10, 8))
x = stats.t.rvs(25, size=nsample)
res = stats.probplot(x, plot=plt)
两种正态分布的混合
nsample = 100
plt.figure(figsize=(10, 8))
x = stats.norm.rvs(loc=[0,5], scale=[1,1.5],size=(nsample,2)).ravel()
res = stats.probplot(x, plot=plt)
loggamma分布
plt.figure(figsize=(10, 8))
x = stats.loggamma.rvs(c=2.5, size=500)
stats.probplot(x, dist=stats.loggamma, sparams=(2.5,), plot=plt)
4 正态的相关系数
例如序列x = [-1.0, -0.1, 0.16, 0.41, 0.62, 0.8, 1.26, 1.54, 1.71, 2.3]
则均值sum(x)/len(x) = 0.77
概率水平
n =10
list(map(lambda x:(x-0.5)/n, range(1, n+1)))
[0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
对应的分位数为
map(lambda x:stats.norm.ppf((x-0.5)/n), range(1, n+1))
为了求相关系数,先求三个数,然后计算rq
x = [-1.0, -0.1, 0.16, 0.41, 0.62, 0.8, 1.26, 1.54, 1.71, 2.3]
n=len(x)
x_ = sum(x)/n
r1 = sum(map(lambda x: (x[0]-x_)*x[1], zip(x, map(lambda x:stats.norm.ppf((x-0.5)/n), range(1, n+1)))))
r2 = sum(map(lambda x: (x-x_)*(x-x_), x))
r3 = sum(map(lambda x:stats.norm.ppf((x-0.5)/n)*stats.norm.ppf((x-0.5)/n), range(1, n+1)))
rq = r1/(np.sqrt(r2)*np.sqrt(r3))
rq = 0.9943587408592187
在显著性水平10%下,把rq = 0.9943587408592187与查表n=10, a=0.10相对照,进行正态性检验,则rq>0.9341 ,因此不拒绝正态性假定
5 柯尔莫可洛夫-斯米洛夫检验Kolmogorov-Smirnov test
柯尔莫哥洛夫-斯米尔诺夫检验(以下简称K-S检验)是用累计次数或累计频率来判断两组数据之间是否存在显著差异的方法。它是将需要做统计分析的数据和另一组标准数据进行对比,求得它和标准数据之间的偏差的方法。
蓝线表示数据,红线表示假设假定符合的分布。
而X轴表示数据值的大小,Y轴表示的数据累计所占百分比。如果简单理解实际上就是概率密度函数的积分。这这个图里面红线实际上就是正态分布的情况,而蓝线因为是离散化的数据,所以呈现的是阶梯状。两条线之间的最大距离也就是黑色箭头表现的位置就表示了二者之间的最大区别程度,称为D,D值的大小则决定了两组数据间的差异。用这种百分数的差别来表现差异,有一个最明显的好处,那就是不会因为某一个点的异常而否定所以的点。此外,KEST还可以检验多种分布,只需要把红线换成其他的线即可。
到这里我们仅仅得到了D值,还不能完全判定两者的符合程度,这时候还需要引入显著度α(alpha默认为0.05)
kstest(x, 'norm')
KstestResult(statistic=0.36355946289143287, pvalue=0.1084952486818282)
由于pvalue=0.1084952486818282 > 0.05 因此不能拒绝原来假设
6 夏皮罗-威尔克检验
该检验是由S.S.Shapiro与M.B.Wilk提出的,又被称之为W检验,主要检验研究对象是否符合正态分布。假设: 一定样本量n(8<n<50)的研究对象总是符合正态分布。
将样本量为n的样本按照大小顺序编排,然后根据公式计算统计量W的值,该值越接近于1,且显著水平大于0.05时,我们就没法拒绝原假设
xi为排序后的样本数据,ai为待估常量,统计量越大则表示数据越符合正态分布,但是仅凭这一个参数是不够的,在非正态分布的小样本数据中也经常会出现较大的W值。该统计量的分布是未知的,因此需要通过模拟或者查表来估计其概率。由于原假设是其符合正态分布,所以当P值小于指定显著水平时表示其不符合正态分布。
x = [-1.0, -0.1, 0.16, 0.41, 0.62, 0.8, 1.26, 1.54, 1.71, 2.3]
stats.shapiro(x)
(0.9899559020996094, 0.9967610239982605)
0.9967610239982605>0.05 妥妥的正态分布
7 正态性检测汇总
from statsmodels.stats.diagnostic import lillifors
group1=[2,3,7,2,6]
group2=[10,8,7,5,10]
group3=[10,13,14,13,15]
list_groups=[group1,group2,group3]
list_total=group1+group2+group3
#正态分布测试
def check_normality(testData):
#20<样本数<50用normal test算法检验正态分布性
if 20<len(testData) <50:
p_value= stats.normaltest(testData)[1]
if p_value<0.05:
print("use normaltest")
print("data are not normal distributed")
return False
else:
print("use normaltest")
print("data are normal distributed")
return True
#样本数小于50用Shapiro-Wilk算法检验正态分布性
if len(testData) <50:
p_value= stats.shapiro(testData)[1]
if p_value<0.05:
print("use shapiro:")
print("data are not normal distributed")
return False
else:
print("use shapiro:")
print("data are normal distributed")
return True
if 300>=len(testData) >=50:
p_value= lillifors(testData)[1]
if p_value<0.05:
print("use lillifors:")
print("data are not normal distributed")
return False
else:
print("use lillifors:")
print("data are normal distributed")
return True
if len(testData) >300:
p_value= stats.kstest(testData,'norm')[1]
if p_value<0.05:
print("use kstest:")
print("data are not normal distributed")
return False
else:
print( "use kstest:")
print("data are normal distributed")
return True
#对所有样本组进行正态性检验
def NormalTest(list_groups):
for group in list_groups:
#正态性检验
status=check_normality(group1)
if status==False :
return False
#对所有样本组进行正态性检验
NormalTest(list_groups)