Kruskal-Wallis 检验后多重比较:Dunn 检验在 Python 中的 3 种实现方案

📅 2026/7/8 23:00:56
Kruskal-Wallis 检验后多重比较:Dunn 检验在 Python 中的 3 种实现方案
Kruskal-Wallis 检验后多重比较Dunn 检验在 Python 中的 3 种实现方案当我们在数据分析中发现多个独立样本组间存在显著差异时仅仅知道存在差异往往远远不够。真正的价值在于明确具体哪些组别之间存在差异这正是多重比较方法的价值所在。本文将重点探讨 Kruskal-Wallis 检验显著后如何进行 Dunn 检验的多重比较并详细介绍三种 Python 实现方案。1. 非参数检验与多重比较基础在比较三个或更多独立样本组时当数据不满足正态分布或方差齐性假设时Kruskal-Wallis 检验成为 ANOVA 的非参数替代方法。该检验基于秩次而非原始数据值通过比较各组秩和来判断组间差异。关键概念区分Kruskal-Wallis 检验整体检验判断是否存在至少一组与其他组不同Dunn 检验事后检验确定具体哪些组对存在差异注意只有当 Kruskal-Wallis 检验结果显著通常 p 0.05时才需要进行后续的多重比较。常见的 p 值校正方法包括校正方法公式适用场景Bonferroniα/m (m为比较次数)比较次数较少时保守可靠Sidak1-(1-α)^(1/m)比 Bonferroni 稍强功效Holm逐步调整平衡保守性与检验力2. 手动实现 Dunn 检验理解 Dunn 检验的计算原理有助于我们更好地应用现成的工具包。下面展示如何从零开始计算 Dunn 检验统计量import numpy as np from scipy import stats import itertools def dunn_test(data_groups, alpha0.05, methodbonferroni): 手动实现 Dunn 检验 参数: data_groups: 列表的列表每个子列表代表一个组的数据 alpha: 显著性水平 method: p值校正方法 (bonferroni或sidak) 返回: 包含组对比较结果的字典 # 合并所有数据并分配秩次 all_data np.concatenate(data_groups) ranks stats.rankdata(all_data) # 计算每组平均秩次 group_ranks [] start 0 for group in data_groups: n len(group) group_ranks.append(np.mean(ranks[start:startn])) start n # 总样本量和组数 N len(all_data) k len(data_groups) # 计算标准误差 SE np.sqrt(N*(N1)/12 * (1/sum(len(g) for g in data_groups))) # 进行所有组对比较 comparisons list(itertools.combinations(range(k), 2)) results [] for i, j in comparisons: z (group_ranks[i] - group_ranks[j]) / SE p 2 * (1 - stats.norm.cdf(abs(z))) # 双侧检验 # p值校正 m len(comparisons) if method bonferroni: p_adj min(p * m, 1.0) elif method sidak: p_adj 1 - (1 - p)**m else: raise ValueError(不支持的校正方法) results.append({ group1: i, group2: j, z: z, p: p, p_adj: p_adj, significant: p_adj alpha }) return results使用示例# 示例数据 group_A [28, 30, 33, 35, 38] group_B [22, 25, 26, 28, 29] group_C [18, 20, 21, 23, 24] # 执行Dunn检验 results dunn_test([group_A, group_B, group_C], methodbonferroni) for res in results: print(f组{res[group1]1} vs 组{res[group2]1}: z{res[z]:.3f}, p_adj{res[p_adj]:.4f})3. 使用 scikit-posthocs 进行 Dunn 检验scikit-posthocs 是专门用于事后检验的 Python 库提供了便捷的 Dunn 检验实现import scikit_posthocs as sp import pandas as pd # 准备数据 (长格式) data pd.DataFrame({ values: group_A group_B group_C, groups: [A]*5 [B]*5 [C]*5 }) # 执行Dunn检验 dunn_results sp.posthoc_dunn(data, val_colvalues, group_colgroups, p_adjustbonferroni) print(dunn_results)scikit-posthocs 的优势包括支持多种 p 值校正方法bonferroni, sidak, holm 等输出清晰的矩阵格式结果内置可视化功能结果解读示例ABCA1.00000.02140.0008B0.02141.00000.1423C0.00080.14231.0000表格中的数值表示调整后的 p 值。例如 A 组与 C 组比较的 p0.0008 0.05表明这两组存在显著差异。4. 使用 pingouin 进行 Dunn 检验pingouin 是另一个强大的统计库提供了更丰富的输出信息import pingouin as pg # 执行Kruskal-Wallis检验 kw pg.kruskal(datadata, dvvalues, betweengroups) print(kw) # 如果Kruskal-Wallis显著进行Dunn检验 if kw[p-unc][0] 0.05: dunn pg.pairwise_ttests( datadata, dvvalues, betweengroups, parametricFalse, padjustbonf ) print(dunn)pingouin 的特点自动检查 Kruskal-Wallis 结果是否显著提供效应量等额外指标结果以 DataFrame 形式呈现便于后续处理5. 方法比较与选择建议三种实现方式的对比特性手动实现scikit-posthocspingouin易用性低高中灵活性高中中输出信息基础丰富最丰富可视化支持无有无依赖项少多中选择建议快速分析使用 scikit-posthocs全面报告使用 pingouin教学/自定义需求手动实现实际项目中我通常会先使用 pingouin 进行初步分析当需要更灵活的多重比较调整时转向 scikit-posthocs。对于教育目的或需要完全控制计算过程的情况手动实现提供了最好的学习机会。