在统计学中,存在着数百种假设检验。而在数据分析、机器学习项目中,只有一小部分较常使用。本文介绍了17种常用的假设检验,包括适用场景及使用Python API的例子。让我们一起来学习吧!
目录
1. 正态分布检验
1.1 Shapiro-Wilk Test(W 检验)
1.2 D’Agostino’s Test
1.3 Anderson-Darling Test
2. 相关性检验
2.1 Pearson相关系数
2.2 Spearman等级相关
2.3 Kendall等级相关
2.4 Chi-Squared Test卡方检验
3. 参数检验
3.1 学生t检验
3.2 配对样本的t检验
3.3 方差分析ANOVA
3.4 重复观测的方差分析
4. 非参数检验
4.1 Mann-Whitney U Test
4.2 Wilcoxon Signed-Rank Test
4.3 Kruskal-Wallis H Test
4.4 Friedman Test
5. 时间序列的平稳性检验
5.1 Augmented Dickey-Fuller Unit Root Test
5.2 Kwiatkowski-Phillips-Schmidt-Shin
用于检验样本数据是否来自服从正态分布的总体。
在实际应用中,W 检验被认为是一个可靠的正态性检验,但是也有人认为该检验更适用于较小的数据样本(数千个观测值以内)。
使用前提:
原假设:样本数据服从正态分布
Python实现代码:
# Shapiro-Wilk Normality Test
from scipy.stats import shapiro
data = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
stat, p = shapiro(data)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('不能拒绝原假设,样本数据服从正态分布')
else:
print('不服从正态分布')
用于检验样本数据是否来自服从正态分布的总体。
D’Agostino’s Test是通过计算样本数据的峰度和偏度,来判断其分布是否偏离正态分布。
使用前提:
原假设:样本数据服从正态分布
Python实现代码:
# D'Agostino's K^2 Normality Test
from scipy.stats import normaltest
data = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
stat, p = normaltest(data)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('不能拒绝原假设,样本数据服从正态分布')
else:
print('不服从正态分布')
用于检验样本数据是否服从某一已知分布。
该检验修改自一种更复杂的非参数的拟合良好的检验统计(Kolmogorov-Smirnov Test)。SciPy中的anderson()
函数实现了Anderson-Darling检验,函数参数为样本数据及要检验的分布名称,默认情况下,为'norm'正态分布,还支持对'expon'指数分布,'logistic'分布,以及'gumbel'耿贝尔分布的检验,它会返回一个包含不同显著性水平下的p值的列表,而不是一个单一的p值,因此这可以更全面地解释结果。
使用前提:
原假设:样本数据服从某一已知分布
Python实现代码:
# Anderson-Darling Normality Test
from scipy.stats import anderson
data = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
result = anderson(data)
print('stat=%.3f' % (result.statistic))
for i in range(len(result.critical_values)):
sl, cv = result.significance_level[i], result.critical_values[i]
if result.statistic print('显著性水平为%.2f时,P值为%.1f,不能拒绝原假设,样本数据服从正态分布' % (sl/100, cv))
else:
print('显著性水平为%.2f时,P值为%.1f, 拒绝原假设,样本数据不服从正态分布' % (sl/100, cv))
# stat=0.424
# 显著性水平为0.15时,P值为0.5,不能拒绝原假设,样本数据服从正态分布
# 显著性水平为0.10时,P值为0.6,不能拒绝原假设,样本数据服从正态分布
# 显著性水平为0.05时,P值为0.7,不能拒绝原假设,样本数据服从正态分布
# 显著性水平为0.03时,P值为0.8,不能拒绝原假设,样本数据服从正态分布
# 显著性水平为0.01时,P值为0.9,不能拒绝原假设,样本数据服从正态分布
用于检验两样本数据之间线性关系的强度。
该检验将两个变量之间的协方差进行归一化处理以给出可解释的分数,为一个介于-1到1之间的值,-1表示完全负相关,1表示完全正相关,0表示没有相关性。
使用前提:
原假设:两变量相互独立
Python实现代码:
# Pearson's Correlation test
from scipy.stats import pearsonr
data1 = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
data2 = [0.353, 3.517, 0.125, -7.545, -0.555, -1.536, 3.350, -1.578, -3.537, -1.579]
stat, p = pearsonr(data1, data2)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('两变量相互独立')
else:
print('两变量可能存在线性相关关系')
用于检验两变量是否具有单调关系。
当两变量因非线性关系相关,或者不服从正态分布时,Spearman相关系数可以用来反映变量间的相关性强度。如果存在线性关系,也可以使用这种方法来检验,但是可能导致计算出的相关系数较低。
Spearman不是使用样本数据本身的协方差和标准差来计算相关系数的,而是根据样本值的相对秩次来计算统计量,这是非参数统计中常用的方法。
使用前提:
原假设:两变量相互独立
Python实现代码:
# Spearman's Rank Correlation Test
from scipy.stats import spearmanr
data1 = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
data2 = [0.353, 3.517, 0.125, -7.545, -0.555, -1.536, 3.350, -1.578, -3.537, -1.579]
stat, p = spearmanr(data1, data2)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('两变量相互独立')
else:
print('两变量可能存在相关关系')
用于检验两变量是否具有单调关系。
使用前提:
原假设:两变量相互独立
Python实现代码:
# Kendall's Rank Correlation Test
from scipy.stats import kendalltau
data1 = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
data2 = [0.353, 3.517, 0.125, -7.545, -0.555, -1.536, 3.350, -1.578, -3.537, -1.579]
stat, p = kendalltau(data1, data2)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('两变量相互独立')
else:
print('两变量可能存在相关关系')
用于检验两分类变量是否相关。
卡方检验的零假设是一个分类变量的观测频数与该分类变量的期望频数相吻合。检验统计量服从卡方分布。
使用前提:
原假设:两变量相互独立
Python实现代码:
# Chi-squared test with similar proportions
from scipy.stats import chi2_contingency
from scipy.stats import chi2
# 列联表
table = [[10, 20, 30],
[6, 9, 17]]
print('列联表')
print(table)
stat, p, dof, expected = chi2_contingency(table)
print('自由度dof=%d' % dof)
print('期望分布')
print(expected)
# [[10.43478261 18.91304348 30.65217391]
# [ 5.56521739 10.08695652 16.34782609]]
# 采用统计量推断
prob = 0.95
critical = chi2.ppf(prob, dof)
print('probability=%.3f, critical=%.3f, stat=%.3f' % (prob, critical, stat))
if abs(stat) >= critical:
print('拒绝原假设,两变量存在相关关系')
else:
print('不能拒绝原假设,两变量相互独立')
# 采用p值推断
alpha = 1.0 - prob
print('significance=%.3f, p=%.3f' % (alpha, p))
if p <= alpha:
print('拒绝原假设,两变量存在相关关系')
else:
print('不能拒绝原假设,两变量相互独立')
用于检验两独立样本数据的均值是否存在显著差异。
使用前提:
原假设:两样本集的均值相同
Python实现代码:
# Student's t-test
from scipy.stats import ttest_ind
data1 = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
data2 = [1.142, -0.432, -0.938, -0.729, -0.846, -0.157, 0.500, 1.183, -1.075, -0.169]
stat, p = ttest_ind(data1, data2)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('不能拒绝原假设,两样本集分布相同')
else:
print('拒绝原假设,样本集分布可能不同')
用于检验两配对样本的均值是否存在显著差异。
使用前提:
原假设:各样本集的均值相同
Python实现代码:
# Paired Student's t-test
from scipy.stats import ttest_rel
data1 = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
data2 = [1.142, -0.432, -0.938, -0.729, -0.846, -0.157, 0.500, 1.183, -1.075, -0.169]
stat, p = ttest_rel(data1, data2)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('不能拒绝原假设,两样本集分布相同')
else:
print('拒绝原假设,两样本集分布可能不同')
用于检验两个及以上独立样本数据的均值是否存在显著差异。
使用前提:
原假设:各样本集均值相同
Python实现代码:
# Analysis of Variance Test
from scipy.stats import f_oneway
data1 = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
data2 = [1.142, -0.432, -0.938, -0.729, -0.846, -0.157, 0.500, 1.183, -1.075, -0.169]
data3 = [-0.208, 0.696, 0.928, -1.148, -0.213, 0.229, 0.137, 0.269, -0.870, -1.204]
stat, p = f_oneway(data1, data2, data3)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('不能拒绝原假设,样本集分布相同')
else:
print('拒绝原假设,样本集分布可能不同')
用于检验两或多配对样本的均值是否存在显著差异。
使用前提:
Python中Scipy暂不支持该检验
用于检验两独立样本分布是否相同。该检验的原理是,将两样本集合并起来,一起排序,然后计算两样本的值是随机混合排序的,还是聚集的。秩序随机则代表两样本集分布无差异,而出现样本值聚集情况则表明有差异。为了使检验有效,要求每个样本数据至少有20个观测值。
使用前提:
原假设:两样本集分布相同
Python实现代码:
# Mann-Whitney U Test
from scipy.stats import mannwhitneyu
data1 = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
data2 = [1.142, -0.432, -0.938, -0.729, -0.846, -0.157, 0.500, 1.183, -1.075, -0.169]
stat, p = mannwhitneyu(data1, data2)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('不能拒绝原假设,两样本集分布相同')
else:
print('拒绝原假设,样本集分布可能不同')
用于检验两配对样本分布是否相同。
样本不独立,因此不能使用Mann-Whitney U检验,而是使用Wilcoxon符号秩检验。这相当于配对样本的学生t检验,但是适用于定序数据,而不是服从正态分布的实测数据。
使用前提:
原假设:两样本集分布相同
Python实现代码:
# Wilcoxon Signed-Rank Test
from scipy.stats import wilcoxon
data1 = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
data2 = [1.142, -0.432, -0.938, -0.729, -0.846, -0.157, 0.500, 1.183, -1.075, -0.169]
stat, p = wilcoxon(data1, data2)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('不能拒绝原假设,两样本集分布相同')
else:
print('拒绝原假设,样本集分布可能不同')
用于检验两个及以上独立样本的分布是否相同。
Kruskal-Wallis 检验是单因素方差分析检验的非参数版本,可以用来确定两个以上的独立样本是否有不同的分布,可以被认为是Mann-Whitney U检验的一般化。该检验的零假设是“所有样本数据从同一个分布中抽取的”,若拒绝原假设,则表明有足够证据证明至少有一个样本与其他样本不同,但是该假设并不能确定具体是哪几个不同。因此,如果需要确定,可再使用Mann-Whitney检验进行两两对比。
使用前提:
原假设:各样本集的分布相同 备择假设:至少有一个样本集与其他样本不同
Python实现代码:
# Kruskal-Wallis H Test
from scipy.stats import kruskal
data1 = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
data2 = [1.142, -0.432, -0.938, -0.729, -0.846, -0.157, 0.500, 1.183, -1.075, -0.169]
data3 = [-0.208, 0.696, 0.928, -1.148, -0.213, 0.229, 0.137, 0.269, -0.870, -1.204]
stat, p = kruskal(data1, data2, data3)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('不能拒绝原假设,样本集分布相同')
else:
print('拒绝原假设,样本集分布可能不同')
用于检验两个及以上配对样本的分布是否相同。Friedman Test是重复测量方差分析的非参数版本,需要每组至少有10个样本,当得出显著性结果,表明至少有一个样本与其他样本存在差异。
使用前提:
原假设:各样本集的分布相同
Python实现代码:
# Friedman Test
from scipy.stats import friedmanchisquare
data1 = [0.873, 2.817, 0.121, -0.945, -0.055, -1.436, 0.360, -1.478, -1.637, -1.869]
data2 = [1.142, -0.432, -0.938, -0.729, -0.846, -0.157, 0.500, 1.183, -1.075, -0.169]
data3 = [-0.208, 0.696, 0.928, -1.148, -0.213, 0.229, 0.137, 0.269, -0.870, -1.204]
stat, p = friedmanchisquare(data1, data2, data3)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('不能拒绝原假设,样本集分布相同')
else:
print('拒绝原假设,样本集分布可能不同')
下面是针对时间序列数据的平稳性检验。直、当数据没有呈现明显的模式特征的话(趋势性、季节性),可认为它是平稳的。平稳序列中各观察值在某个固定水平上波动,虽然在不同时间段波动程度不同,但是并不存在某种规律,可认为是随机的。
用于检验时间序列是否具有单位根,例如是否具有趋势或者更普遍的自回归。单位根是时间序列的一种特性,使时间序列具有非平稳性。单位根的存在意味着时间序列是非平稳的。
使用前提:
原假设:存在一个单位根,序列是非平稳的 备择假设:不存在单位根,序列平稳 (注意:该检验的原假设与下一个检验的假设是不同的;如果p值小于显著性水平,认为该时间序列平稳)
Python实现代码:
# Augmented Dickey-Fuller unit root test
from statsmodels.tsa.stattools import adfuller
data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
stat, p, lags, obs, crit, t = adfuller(data)
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('时间序列是不平稳的')
else:
print('时间序列平稳')
用于检验时间序列在确定性趋势上的平稳性。
使用前提:
Python实现代码:
注意,在默认情况下,该函数参数regression='c'
,代表 原假设:时间序列是平稳的。(围绕一个常数) 备择假设:时间序列是不平稳的。
# Kwiatkowski-Phillips-Schmidt-Shin test
# The data is stationary around a constant (default).
from statsmodels.tsa.stattools import kpss
data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
stat, p, lags, crit = kpss(data, regression='c')
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('时间序列是平稳的')
else:
print('时间序列是不平稳的')
# stat=0.410, p=0.073
# 时间序列是平稳的
而使参数regression='ct'
,可检验时间序列在确定趋势上的平稳性。
# Kwiatkowski-Phillips-Schmidt-Shin test
# The data is stationary around a trend
from statsmodels.tsa.stattools import kpss
data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
stat, p, lags, crit = kpss(data, regression='ct')
print('stat=%.3f, p=%.3f' % (stat, p))
if p > 0.05:
print('时间序列是趋势稳定的')
else:
print('时间序列是趋势不稳定的')
# stat=0.433, p=0.010
# 时间序列是趋势不稳定的
·················END·················参考资料:
https://machinelearningmastery.com/statistical-hypothesis-tests-in-python-cheat-sheet/
说说心里话
写给所有数据人。
从留存率业务案例谈0-1的数据指标体系
NB,真PDF神处理工具!
超级菜鸟如何入门数据分析?
欢迎长按扫码关注「数据管道」