1. Python统计假设检验速查手册
在机器学习项目中,统计假设检验是验证数据特征和模型效果的重要工具。虽然统计学中存在数百种假设检验方法,但实际项目中常用的只有一小部分。本文将介绍17种最常用的统计假设检验方法,并提供Python实现示例。
提示:统计检验的结果是概率性的而非确定性的,因此针对同一问题采用不同检验方法可能会得出不同结论。这是统计分析的正常现象。
2. 正态性检验
正态性检验用于验证数据是否服从正态分布,这是许多参数检验的前提条件。
2.1 Shapiro-Wilk检验
检验目的:评估样本数据是否来自正态分布总体。
关键假设:
- 样本观测值独立同分布(iid)
- 样本量通常在3到5000之间效果最佳
Python实现:
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(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('样本可能服从正态分布') else: print('样本可能不服从正态分布')注意事项:
- 对小样本(3-50)效果最好
- 对偏离峰度和偏度的分布敏感
- 实际应用中,p值略小于0.05时仍需结合其他检验判断
2.2 D'Agostino K²检验
检验目的:通过偏度和峰度评估样本正态性。
关键假设:
- 样本观测值独立同分布(iid)
- 样本量建议至少20个以上
Python实现:
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(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('样本可能服从正态分布') else: print('样本可能不服从正态分布')实操心得:
- 该检验对样本量较敏感,小样本容易得出"非正态"结论
- 可结合直方图或Q-Q图进行综合判断
- 适用于中等到大样本量(>50)的情况
2.3 Anderson-Darling检验
检验目的:基于经验分布函数的正态性检验,对尾部差异特别敏感。
关键假设:
- 样本观测值独立同分布(iid)
- 参数需指定分布类型(默认为正态)
Python实现:
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(f'统计量={result.statistic:.3f}') for i in range(len(result.critical_values)): sl, cv = result.significance_level[i], result.critical_values[i] if result.statistic < cv: print(f'在{sl}%显著性水平下,样本可能服从正态分布') else: print(f'在{sl}%显著性水平下,样本可能不服从正态分布')经验技巧:
- 比Shapiro-Wilk检验对尾部偏离更敏感
- 适用于各种样本量
- 可检验其他分布类型(如指数、极值等)
3. 相关性检验
相关性检验用于评估变量间的统计关联程度。
3.1 Pearson相关系数
检验目的:衡量两个连续变量间的线性相关程度。
关键假设:
- 变量为连续数据
- 变量服从正态分布
- 变量间存在线性关系
- 同方差性
Python实现:
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(f'相关系数={stat:.3f}, p值={p:.3f}') if p > 0.05: print('变量可能独立') else: print('变量可能相关')注意事项:
- 对异常值敏感
- 只能检测线性关系
- 相关系数绝对值越大表示相关性越强
- 建议同时绘制散点图辅助判断
3.2 Spearman秩相关
检验目的:评估两个变量的单调关系。
关键假设:
- 变量至少是有序的
- 单调关系(不一定是线性)
Python实现:
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(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('变量可能独立') else: print('变量可能相关')优势:
- 不受异常值影响
- 适用于非线性单调关系
- 可用于有序分类变量
3.3 Kendall秩相关
检验目的:基于一致对和非一致对评估变量关联性。
关键假设:
- 变量至少是有序的
- 单调关系
Python实现:
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(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('变量可能独立') else: print('变量可能相关')适用场景:
- 小样本数据
- 存在较多重复值的数据
- 需要更稳健的相关性度量时
3.4 卡方检验
检验目的:检验两个分类变量的独立性。
关键假设:
- 观测值相互独立
- 每个单元格期望频数≥5
- 总样本量≥50
Python实现:
from scipy.stats import chi2_contingency table = [[10, 20, 30], [6, 9, 17]] stat, p, dof, expected = chi2_contingency(table) print(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('变量可能独立') else: print('变量可能相关')注意事项:
- 当期望频数<5时考虑Fisher精确检验
- 对于2×2表格建议使用Yates校正
- 只能说明有关联,不能说明关联强度
4. 平稳性检验
平稳性检验用于时间序列分析,验证序列的统计特性是否随时间变化。
4.1 ADF检验
检验目的:检测时间序列中的单位根(判断是否平稳)。
关键假设:
- 观测值按时间顺序排列
- 可包含常数项或趋势项
Python实现:
from statsmodels.tsa.stattools import adfuller data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] result = adfuller(data) print(f'ADF统计量={result[0]:.3f}') print(f'p值={result[1]:.3f}') print('临界值:') for key, value in result[4].items(): print(f'\t{key}: {value:.3f}') if result[1] > 0.05: print('序列可能非平稳') else: print('序列可能平稳')参数选择:
- 回归类型(常数、趋势、无)
- 滞后阶数(可用AIC/BIC自动选择)
- 对季节性数据需先进行差分
4.2 KPSS检验
检验目的:检验时间序列的趋势平稳性。
关键假设:
- 观测值按时间顺序排列
- 可包含常数项或趋势项
Python实现:
from statsmodels.tsa.stattools import kpss data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] result = kpss(data) print(f'KPSS统计量={result[0]:.3f}') print(f'p值={result[1]:.3f}') print('临界值:') for key, value in result[3].items(): print(f'\t{key}: {value:.3f}') if result[1] < 0.05: print('序列可能非平稳') else: print('序列可能平稳')与ADF检验的区别:
- ADF的H0是非平稳,KPSS的H0是平稳
- 通常两者结合使用:
- ADF拒绝且KPSS不拒绝→平稳
- ADF不拒绝且KPSS拒绝→非平稳
- 两者都拒绝或都不拒绝→需进一步分析
5. 参数检验
参数检验用于比较样本均值,要求数据满足正态性等假设。
5.1 独立样本t检验
检验目的:比较两个独立样本的均值差异。
关键假设:
- 独立性
- 正态性
- 方差齐性
Python实现:
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(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('均值可能无显著差异') else: print('均值可能有显著差异')方差不等时的修正:
# 添加equal_var=False参数 ttest_ind(data1, data2, equal_var=False)5.2 配对样本t检验
检验目的:比较两个相关样本的均值差异。
关键假设:
- 观测值成对出现
- 差值服从正态分布
Python实现:
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(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('均值可能无显著差异') else: print('均值可能有显著差异')适用场景:
- 同一对象前后测量
- 匹配设计的实验
- 重复测量数据
5.3 单因素方差分析
检验目的:比较三个或更多独立样本的均值差异。
关键假设:
- 独立性
- 正态性
- 方差齐性
Python实现:
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(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('各组均值可能无显著差异') else: print('至少有两组均值有显著差异')事后检验: 当ANOVA结果显著时,需要进行事后检验(如Tukey HSD)确定具体哪些组间存在差异。
6. 非参数检验
当数据不满足参数检验假设时,使用非参数检验。
6.1 Mann-Whitney U检验
检验目的:比较两个独立样本的中位数差异。
关键假设:
- 独立性
- 数据至少是有序的
Python实现:
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(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('分布可能无显著差异') else: print('分布可能有显著差异')注意事项:
- 对形状差异敏感
- 小样本时使用精确分布
- 大样本时使用正态近似
6.2 Wilcoxon符号秩检验
检验目的:比较两个相关样本的中位数差异。
关键假设:
- 成对观测
- 差值是有序的
Python实现:
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(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('分布可能无显著差异') else: print('分布可能有显著差异')适用场景:
- 不满足配对t检验假设时
- 有序数据但差值不是正态分布
- 存在异常值的情况
6.3 Kruskal-Wallis检验
检验目的:比较三个或更多独立样本的中位数差异。
关键假设:
- 独立性
- 数据至少是有序的
Python实现:
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] stat, p = kruskal(data1, data2) print(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('各组中位数可能无显著差异') else: print('至少有两组中位数有显著差异')事后检验: 结果显著时可进行Dunn检验确定具体差异组别。
6.4 Friedman检验
检验目的:比较三个或更多相关样本的中位数差异。
关键假设:
- 成块设计(如重复测量)
- 数据至少是有序的
Python实现:
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(f'统计量={stat:.3f}, p值={p:.3f}') if p > 0.05: print('各组中位数可能无显著差异') else: print('至少有两组中位数有显著差异')适用场景:
- 重复测量设计
- 区组设计实验
- 不满足重复测量ANOVA假设时
7. 检验选择指南
针对不同数据类型和分析目的,可参考以下检验选择流程:
| 分析目的 | 数据类型 | 样本关系 | 参数检验 | 非参数检验 |
|---|---|---|---|---|
| 比较两组 | 连续 | 独立 | 独立t检验 | Mann-Whitney U |
| 比较两组 | 连续 | 配对 | 配对t检验 | Wilcoxon符号秩 |
| 比较多组 | 连续 | 独立 | 单因素ANOVA | Kruskal-Wallis |
| 比较多组 | 连续 | 配对 | 重复测量ANOVA | Friedman检验 |
| 关联分析 | 连续 | - | Pearson相关 | Spearman/Kendall相关 |
| 关联分析 | 分类 | - | - | 卡方检验 |
实际应用建议:
- 先进行正态性和方差齐性检验
- 根据检验结果选择参数或非参数方法
- 对重要结论使用多种检验方法交叉验证
- 始终结合效应量和置信区间进行解释
- 考虑使用Bootstrap等稳健方法作为补充