)
Python实战用Mann-Whitney U检验对比两种教学方法效果附完整代码在教育研究中我们常常需要评估不同教学方法对学生成绩的影响。传统的t检验虽然常用但它要求数据服从正态分布且方差齐性。当这些条件不满足时Mann-Whitney U检验也称为Wilcoxon秩和检验就成为了一个强有力的替代方案。本文将带你从实际应用角度使用Python完整实现这一统计检验并深入解读结果。1. Mann-Whitney U检验的核心概念Mann-Whitney U检验是一种非参数检验方法它不依赖于数据的具体分布形式。与t检验相比它更适合以下场景样本量较小每组通常小于30数据明显偏离正态分布数据为有序变量ordinal data而非严格的连续变量检验的基本原理将所有观测值混合后排序计算每组的秩和rank sum然后比较两组秩和的差异是否具有统计学意义。如果两种教学方法效果相当那么两组的秩和应该接近如果差异显著则说明其中一种方法更优。注意虽然Mann-Whitney U检验和Wilcoxon秩和检验在两组独立样本情况下是等价的但在配对样本情况下应使用Wilcoxon符号秩检验。2. 实战准备数据与Python环境2.1 示例数据说明假设我们研究两种英语教学方法Method A和Method B的效果每组15名学生期末考试成绩如下method_a [85, 92, 78, 88, 90, 82, 86, 93, 80, 91, 84, 89, 79, 87, 83] method_b [80, 85, 75, 82, 88, 78, 83, 90, 77, 86, 81, 84, 76, 79, 87]2.2 必要的Python库确保已安装以下库pip install numpy scipy pandas matplotlib核心库的作用numpy: 基础数值计算scipy: 提供统计检验函数pandas: 数据整理与分析matplotlib: 数据可视化3. 完整代码实现与逐步解析3.1 数据探索与描述统计在进行正式检验前先了解数据的基本特征import numpy as np from scipy import stats import matplotlib.pyplot as plt # 计算描述性统计量 def describe_data(data, name): print(f\n{name} Statistics:) print(fMean: {np.mean(data):.2f}) print(fMedian: {np.median(data):.2f}) print(fStandard Deviation: {np.std(data):.2f}) print(fMinimum: {np.min(data)}) print(fMaximum: {np.max(data)}) describe_data(method_a, Method A) describe_data(method_b, Method B) # 绘制箱线图对比 plt.figure(figsize(8, 6)) plt.boxplot([method_a, method_b], labels[Method A, Method B]) plt.title(Comparison of Test Scores) plt.ylabel(Score) plt.show()输出结果示例Method A Statistics: Mean: 85.80 Median: 86.00 Standard Deviation: 4.91 Minimum: 78 Maximum: 93 Method B Statistics: Mean: 82.07 Median: 82.00 Standard Deviation: 4.57 Minimum: 75 Maximum: 903.2 执行Mann-Whitney U检验使用scipy的mannwhitneyu函数进行检验# 执行检验 statistic, p_value stats.mannwhitneyu(method_a, method_b, alternativetwo-sided) print(\nMann-Whitney U Test Results:) print(fU statistic: {statistic}) print(fP-value: {p_value:.4f}) # 结果解读 alpha 0.05 if p_value alpha: print(结论拒绝原假设两种教学方法对学生成绩的影响存在显著差异p 0.05) else: print(结论无法拒绝原假设两种教学方法的效果无显著差异)3.3 效应量计算除了p值我们还应计算效应量来衡量差异的实际意义# 计算效应量 n1, n2 len(method_a), len(method_b) effect_size statistic / (n1 * n2) print(f\n效应量Common Language Effect Size: {effect_size:.3f})效应量解释0.5表示无差异0.5表示Method A倾向于更好0.5表示Method B倾向于更好4. 结果可视化与专业报告4.1 可视化呈现# 创建更专业的可视化 plt.figure(figsize(10, 6)) # 小提琴图展示分布 plt.subplot(1, 2, 1) plt.violinplot([method_a, method_b], showmediansTrue) plt.xticks([1, 2], [Method A, Method B]) plt.title(Score Distributions) plt.ylabel(Test Score) # 秩和图示 plt.subplot(1, 2, 2) all_scores method_a method_b ranks stats.rankdata(all_scores) plt.scatter([A]*len(method_a) [B]*len(method_b), ranks, alpha0.6) plt.title(Rank Plot) plt.xlabel(Teaching Method) plt.ylabel(Rank) plt.tight_layout() plt.show()4.2 专业报告要点在学术或专业报告中应包括以下要素检验方法明确说明使用Mann-Whitney U检验的原因如数据不满足正态性描述统计报告每组的中位数、四分位距等检验结果U值精确p值不要只写p0.05效应量结论结合统计意义和实际意义进行解读示例报告语句 采用Mann-Whitney U检验比较两种教学方法的效果结果显示Method A组的成绩显著高于Method B组U65p0.033效应量0.289。尽管差异具有统计显著性但效应量表明实际差异程度中等。5. 进阶应用与注意事项5.1 处理相同值Ties当数据中存在相同值时需要进行校正# 使用校正后的计算方法 statistic, p_value stats.mannwhitneyu(method_a, method_b, methodexact) print(f校正后的p值: {p_value:.4f})5.2 样本量规划如果设计新的研究可以使用功效分析确定所需样本量from statsmodels.stats.power import tt_ind_solve_power # 假设中等效应量0.5 effect_size 0.5 alpha 0.05 power 0.8 required_n tt_ind_solve_power(effect_sizeeffect_size, alphaalpha, powerpower, ratio1) print(f\n每组所需样本量功效80%{int(np.ceil(required_n))})5.3 常见问题解答Q何时选择Mann-Whitney U检验而非t检验数据明显非正态可通过Shapiro-Wilk检验验证样本量小且分布未知数据为有序变量Q检验结果显示显著但效应量很小怎么办统计显著不等于实际意义重大结合领域知识判断差异是否具有实际价值考虑增加样本量验证结果稳定性Q如何处理多于两组的比较使用Kruskal-Wallis检验非参数版的ANOVA如果显著再进行两两比较需校正多重比较6. 完整代码整合以下是可直接运行的完整脚本import numpy as np from scipy import stats import matplotlib.pyplot as plt # 数据 method_a [85, 92, 78, 88, 90, 82, 86, 93, 80, 91, 84, 89, 79, 87, 83] method_b [80, 85, 75, 82, 88, 78, 83, 90, 77, 86, 81, 84, 76, 79, 87] # 描述统计 def describe_data(data, name): print(f\n{name} Statistics:) print(fMean: {np.mean(data):.2f}) print(fMedian: {np.median(data):.2f}) print(fStandard Deviation: {np.std(data):.2f}) describe_data(method_a, Method A) describe_data(method_b, Method B) # Mann-Whitney U检验 statistic, p_value stats.mannwhitneyu(method_a, method_b) print(f\nU statistic: {statistic}) print(fP-value: {p_value:.4f}) # 效应量 effect_size statistic / (len(method_a) * len(method_b)) print(fEffect Size: {effect_size:.3f}) # 可视化 plt.figure(figsize(12, 5)) plt.subplot(1, 2, 1) plt.boxplot([method_a, method_b], labels[Method A, Method B]) plt.title(Score Distribution Comparison) plt.subplot(1, 2, 2) all_scores method_a method_b ranks stats.rankdata(all_scores) plt.scatter([A]*15 [B]*15, ranks, alpha0.6) plt.title(Rank Plot) plt.xlabel(Teaching Method) plt.ylabel(Rank) plt.tight_layout() plt.show()