什么是正态分布?如何进行正态性检验?

Catalogue
  1. 1. 前言
  2. 2. 正态分布
    1. 2.1. 定义
    2. 2.2. 特点
  3. 3. 正态性检验
    1. 3.1. 定义
    2. 3.2. 直方图检验
    3. 3.3. QQ图判断
    4. 3.4. K-S检验
    5. 3.5. K-S算法
  4. 4. 总结

摘要
什么是正态分布,以及检验数据样本的正态性的方式有哪些?

前言

本文记录学习正态分布以及数据特征的正态性检验。

正态分布

正态分布,又名高斯分布,是一个非常常见的连续概率分布。

定义

正态分布是具有两个参数μ和σ2的连续型随机变量的分布。即若一个随机变量X服从一个数学期望为μ、方差为σ2的正态分布,记为N( μ , σ2 )。

参数μ是服从正态分布的随机变量的均值,参数σ2是此随机变量的方差。

其概率密度函数为正态分布的期望值μ决定了其位置,其标准差σ决定了分布的幅度,当μ = 0,σ = 1时的正态分布称之为标准正态分布。

特点

  • 集中性:正态曲线的高峰位于正中央,即均数所在的位置
  • 对称性:正态曲线以均数为中心,左右对称,曲线两端永不于横轴相交
  • 均匀变动性:正态曲线由均数所在处开始,分别向左右两侧逐渐均匀下降
  • 服从正态分布的随机变量的概率规律为取 μ邻近的值的概率大 ,而取离μ越远的值的概率越小;
  • μ决定分布的中心位置
  • σ越大,曲线越矮胖,总体分布越分散,反之曲线越瘦高,总体分布越集中

正态性检验

定义

利用观测数据判断总体是否服从正态分布的检验称为正态性检验,是统计判决中重要的一种特殊的拟合优度假设检验

最为基础和常用的正态性检验方法有:

  • 直方图初判
  • QQ图判断
  • K-S检验

直方图检验

1
2
3
4
5
6
# 导入模块

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 直方图初判

s = pd.DataFrame(np.random.randn(1000)+10,columns=['value'])
print(s.head())

fig = plt.figure(figsize = (16,9))
ax1 = fig.add_subplot(2,1,1)
ax1.scatter(s.index,s.values)
plt.grid()

ax2 = fig.add_subplot(2,1,2)
s.hist(bins = 20,alpha = 0.7,ax = ax2,edgecolor = 'k')
s.plot(kind = 'kde',secondary_y = True,ax = ax2)
plt.grid()
1
2
3
4
5
6
       value
0 10.031998
1 8.938971
2 9.521849
3 10.752110
4 10.601193

QQ图判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# QQ图判断 - 通过把测试样本数据的分位数与已知分布相比较,从而来检验数据的分布情况

# QQ图是一种散点图,对应于正态分布的QQ图,就是由标准正态分布的分位数为横坐标,样本值为纵坐标的散点图

# 参考直线:四分之一分位点和四分之三分位点这两点确定,看散点是否落在这条线的附近


# 绘制思路

# 1、在做好数据清洗后,对数据进行排序
# 2、排序后,计算出每个数据对应的百分位p{i},即第i个数据x(i)为p(i)分位数,其中p(i)=(i-0.5)/n
# 3、绘制直方图 + QQ图 , 直方图做参考

# 绘制散点图,横坐标是它的分位,就是分布的位置,做下排序,看是否很多的点在某条直线上,这条直线一般是拿它的一分位和三分位做一下相减,

s = pd.DataFrame(np.random.randn(1000)+10,columns = ['value'])
print(s.head())

mean = s['value'].mean()
std = s['value'].std()
print('均值为:%.2f,标准差为:%.2f' % (mean,std))
print('------------')

# 计算均值,标准差
s.sort_values(by = 'value',inplace = True)

# 重新排序
s_r = s.reset_index(drop = False)

# 计算百分位数p(i)
# 计算q值

s_r['p'] = (s_r.index - 0.5) / len(s_r)

# 每个值标准化后的结果
s_r['q'] = (s_r['value'] - mean) / std

st = s['value'].describe()

# 1/4位点
x1,y1 = 0.25,st['25%']

# 3/4位点
x2,y2 = 0.75,st['75%']


# 绘制数据分布图 -- 散点图

fig = plt.figure(figsize = (16,12))
ax1 = fig.add_subplot(3,1,1)
ax1.scatter(s.index,s.values)
plt.grid()

# 绘制直方图

ax2 = fig.add_subplot(3,1,2)
s.hist(bins = 30,alpha = 0.7,ax = ax2)
s.plot(kind = 'kde',secondary_y = True,ax = ax2)
plt.grid()

# 绘制QQ图,直线为四分之一位数、四分之三位数的连线,基本符合正态分布

ax3 = fig.add_subplot(3,1,3)
ax3.plot(s_r['p'],s_r['value'],'k.',alpha = 0.1)
ax3.plot([x1,x2],[y1,y2],'-r')
plt.grid()
1
2
3
4
5
6
7
8
       value
0 10.315218
1 11.168954
2 11.468953
3 10.099762
4 8.701746
均值为:10.00,标准差为:1.01
------------


K-S检验

Kolmogorov-Smirnov是比较一个频率分布f(x)与一个理论分布g(x)或者两个观测值分布的检验方法。

以样本数据的累计频数分布与特定的理论分布比较(比如正态分布),如果两者差距小,则推论样本分布取自某特定分布

假设检验问题:

H0:样本的总体分布 服从某特定分布

H1:样本的总体分布 不服从某特定分布

Fn(x):样本的累计分布函数 F0(x):理论分布的分布函数

D:F0(x) 与 Fn(x) 差值的绝对值最大值 即 D= max IFn(x) - F0(x)I

D > D( n , α )相比较:p > 0.05则接受H0,p < 0.05则接受H1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# K - S 检验 → Kolmogorov-Smirnov是比较频率分布f(x)与理论分布g(x)或者两个观测值分布的检验方法

data = [87,77,92,68,80,78,85,77,81,80,80,77,92,86,
76,80,81,75,77,72,81,72,83,86,80,68,77,87,
76,77,78,92,75,80,78]

df = pd.DataFrame(data,columns = ['value'])
jz = df['value'].mean()
bzc = df['value'].std()
print('样本均值为:%.2f,样本标准差为:%.2f' % (jz,bzc))
print('----------------')

s = df['value'].value_counts().sort_index()
df_s = pd.DataFrame({'血糖浓度':s.index,
'次数':s.values})

df_s['累计次数'] = df_s['次数'].cumsum()
df_s['累计频率'] = df_s['累计次数'] / len(data)
df_s['标准化取值'] = (df_s['血糖浓度'] - jz) / bzc
df_s['理论分布'] = [0.0244,0.0968,0.2148,0.2676,0.3228,0.3859,0.5160,0.5793,0.7054,0.8106,
0.8531,0.8888,0.9803]
df_s['D'] = np.abs(df_s['累计频率'] - df_s['理论分布'])
dmax = df_s['D'].max()
print('实际观测D值为:%.4f' % dmax)

df_s
1
2
3
4
样本均值为:79.74,样本标准差为:5.94
----------------
实际观测D值为:0.1636

把一个非标准正态分布变成一个标准正态分布----->把非标准正态分布的值变成X = (x-u) /方差----->可以找到理论值。在将这个标准化取值去跟正态分布表去找对应的值。

因为标准化取值的值它本 身就符合正态分布;系统分布与标准分布相减,如果这个函数满足标准正态分布,它的值就应该满足这个表。比如说标准化取值2.064315,其对应的查正态分布表值为0.9803,它的理论分布值是0.9803; 标准化取值-1.9777,去掉负号,查正态分布表为0.9756,正的是0.9756,负的就是1-0.9756=0.0244.可以看到与理论分布值是相对应的。

理论分布就相当于是g(x)就是F0(x),F(n)就是原来的F(n)累计频率。累计频率 - 理论分布 = D

1
2
3
4
5
6
#绘制折线图

df_s['累计频率'].plot(style = '--k.')
df_s['理论分布'].plot(style = '--r.')
plt.legend(loc = 'upper left')
plt.grid()

结论:实际观测D值为:0.1597 对应的0.1597放到显著性对照表,我们的样本数据一共35个,在50以内,按0.05的值去算的话,0.1587介于0.158和0.190之间,它所对应的P值是0.2和0.4,这个P值是大于0.05的。 拿到这个D值去那个表里边查,如果大于0.05就说明满足正态分布。

K-S算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#直接用算法做KS检验

from scipy import stats

data = [87,77,92,68,80,78,85,77,81,80,80,77,92,86,
76,80,81,75,77,72,81,72,83,86,80,68,77,87,
76,77,78,92,75,80,78]

df = pd.DataFrame(data,columns = ['value'])
jz = df['value'].mean()
bzc = df['value'].std()
stats.kstest(df['value'],'norm',(jz,bzc))
# .kstest 方法:ks检验,参数分别是:待检验数据,检验方法,均值与标准差

# 结果返回两个值:statistic → D值;pvalue → P值
# P值大于0.05,满足正态分布

1
KstestResult(statistic=0.1590868892818147, pvalue=0.3061435516448461)

总结

以上是数据特征分析中的正态分布与正态性检验的全部内容,如有错误,恳请指正,感谢阅读~