ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

手把手拆解非参数统计计算题:秩检验从手算到Python验证

2026/9/17 22:38:00 拓冰建站 浏览量
手把手拆解非参数统计计算题:秩检验从手算到Python验证 简介王静龙《非参数统计分析》课后计算题参考标准答案分享是一份面向统计学专业学生、数据分析和考研备考者的PDF文档旨在帮助读者核对非参数统计课后计算题结果、梳理解题步骤。文件为单个PDF压缩包仅126KB下载后即可直接阅读。内容共包含四道习题的完整解答习题一演示单样本t检验的t统计量、p值与95%置信区间习题二对四个服务机场指标做描述性统计列出均值、标准差、方差、峰度、偏度等结果习题三利用二项式分布及Excel的BINOMDIST、BINOM.INV函数计算累计概率与临界值习题四通过符号检验与符号秩和检验比较两种添加剂效果。每道题在给出数值结果的同时还附有知识点小结便于将计算过程与统计原理对应起来。目前已有2681人学习下载适合课程复习、作业自查或考研备考时对照使用。1. 非参数统计分析的计算题难的不是公式而是秩翻开《非参数统计分析》的课后计算题很多人第一反应是把它当成“不用满足正态假设的 t 检验”然后套公式、查表、写结论。真正动手算过几道才发现卡壳的地方基本都集中在同一处秩怎么排、并列值怎么处理、大样本近似公式里的修正项什么时候该用。符号检验、Wilcoxon 秩和检验、Kruskal-Wallis 检验、Spearman 秩相关这些名字背后对应着同一套“把数据换成秩、在秩上做推断”的框架但每道题的数据形态不同计算路径就完全不同。这篇文章围绕课后计算题最常考的几类题型把每一步计算拆开给出可复现的 Python 计算流程、参数选择和结果核对方法。适合正在啃这本教材、准备统计面试或者工作中需要处理非正态数据的从业者。2. 符号检验与 Wilcoxon 秩和检验的手工计算路径2.1 符号检验从差值到二项分布 p 值的完整推导符号检验sign test是思路最简单的非参数检验配对数据算出差值只看方向不看大小。它不要求差值服从任何特定分布甚至不要求对称代价是丢弃了差值的大小信息检验功效在正态数据下明显低于 t 检验——这个“代价”本身就是考点答题时需要主动写出来。手工计算的完整路径分四步。第一步计算每一对观测的差值 d_i x_i - y_i差值为 0 的样本直接剔除不进入后续计算。第二步记录正差值的个数 k 和负差值的个数 n - k。第三步在零假设“差值中位数为 0”下k 服从二项分布 Binomial(n, 0.5)双侧检验的 p 值为 2 × P(K ≤ min(k, n-k))。第四步与显著性水平比较后下结论。以一组治疗前后血压数据为例患者编号治疗前治疗后差值 d符号1160152-8-2165158-7-3170165-5-416817025155150-5-6172160-12-7180171-9-8162155-7-9158154-4-10175168-7-正差值 1 个负差值 9 个n 10。min(1, 9) 1双侧 p 值 2 × [C(10,0) C(10,1)] / 2^10 2 × 11 / 1024 ≈ 0.0215在 α 0.05 下拒绝“治疗前后无差异”的零假设。这里的细节在于为什么不取 P(K ≤ 1) 而是乘 2因为双侧检验要同时考虑“正号过少”和“负号过少”两个方向而二项分布对称k 和 n-k 的概率相等所以直接乘 2。提示手算时最容易忽略的是差值为 0 的样本。严格做法是从 n 中剔除同时在实际报告中说明剔除了几对。有些教材会在这一步使用“修正”或“忽略”两种口径得到的 p 值不同答题时务必注明。2.2 Wilcoxon 秩和检验秩的分配与 U 统计量Wilcoxon 秩和检验也叫 Mann-Whitney U 检验解决了符号检验“只看方向、丢大小”的缺陷。它把两组数据合并后统一排序用秩次替代原始数值再比较两组的秩和。相比符号检验它利用了更多信息在数据接近正态时功效接近 t 检验在重尾分布下往往优于 t 检验。手工计算分三步。第一步将两组数据合并并从小到大排序对每个观测分配秩次遇到并列值时取平均秩。第二步分别计算两组的秩和 R1 和 R2。第三步计算 U 统计量U1 R1 - n1(n11)/2U2 R2 - n2(n21)/2理论上 U1 U2 n1 × n2这是检验计算是否正确的重要校验条件。检验时取 U min(U1, U2)。以一个两组独立样本的比较为例组别观测值合并排序秩次A8274(B)1A8876(A)2A7677(B)3A9179(A)4A7980(B)5A8582(A)6B7483(B)7B8385(A)8B8087(B)9B8788(A)10B7791(A)11A 组秩次为 {2, 4, 6, 8, 10, 11}R1 41B 组秩次为 {1, 3, 5, 7, 9}R2 25。n1 6n2 5代入公式U1 41 - 6×7/2 20U2 25 - 5×6/2 10U1 U2 30 6×5校验通过。取 U 10。一个容易混淆的点题目可能给的是两组各自的均值、方差而非原始数据这时不能直接做秩和检验——秩的计算基于原始观测的排序均值相同的两组数据可能秩分布完全不同。如果题目只给汇总统计量说明它想考察的知识点不是秩和检验而是正态近似框架下的两样本检验审题时要先分辨清楚。2.3 临界值查表与正态近似样本量边界怎么判断拿到 U 统计量之后查表还是用正态近似取决于样本量。传统的判断标准是当 min(n1, n2) ≤ 20 时查 Wilcoxon 秩和检验临界值表超过这个范围才使用正态近似。但现在的统计软件已经能算出精确 p 值手算题的价值更多在于理解近似公式的结构。正态近似的公式为μ_U n1 × n2 / 2σ_U √(n1 × n2 × (n1 n2 1) / 12)Z (U - μ_U) / σ_U用上面的例子μ_U 15σ_U √(30 × 12 / 12) √30 ≈ 5.48Z (10 - 15) / 5.48 ≈ -0.91双侧 p 值约为 0.36不拒绝原假设。这里的要点在于U 的期望是 n1 × n2 / 2也就是说两组没有差异时 U 应该在中间值附近偏离越远越有理由拒绝。手算时还要注意一个问题查表得到的是某显著性水平下的临界值不同教材的表格方向不一致——有的表给的是较小的 U 临界值有的给的是较大的秩和临界值。做题前先看表格的说明确定它列的是 U 还是 R否则很容易把结论判断反。3. 用 Python 复算课后计算题的完整流程3.1 把课后题整理成标准数据格式课后题的数据呈现形式通常有三种两组原始数据、配对差值数据、汇总的频数表。用 Python 复算的第一步是把它们统一成“行 观测、列 变量”的长表或宽表。对于独立两组比较推荐使用长格式一列是观测值一列是组标签。配对数据则用宽格式两个变量各占一列行是一对观测。import numpy as np import pandas as pd from scipy import stats # 独立两组数据 group_a np.array([82, 88, 76, 91, 79, 85]) group_b np.array([74, 83, 80, 87, 77]) # 造成长格式 DataFrame df pd.DataFrame({ value: np.concatenate([group_a, group_b]), group: [A] * len(group_a) [B] * len(group_b) }) print(df.head())这里把两组数据合并成单列并附上组标签生成的是长格式数据。后续所有按组聚合的操作求和、计数、排序都建立在这个结构上。3.2 手写符号检验与 Wilcoxon 秩和检验函数先用 Python 完整手写一遍计算逻辑而不直接调 scipy 封装好的函数。这样做的意义在于你能看到每一行代码对应教材里的哪一个公式出问题时才知道去哪一步排查。def sign_test(x, yNone, median0): 符号检验检验配对差值或单样本中位数 if y is not None: d np.asarray(x) - np.asarray(y) else: d np.asarray(x) - median # 剔除差值为 0 的观测 d d[~np.isclose(d, 0)] n len(d) pos np.sum(d 0) neg n - pos k min(pos, neg) # 双侧检验2 * P(K k) p_value 2 * stats.binom.cdf(k, n, 0.5) return {n: n, pos: int(pos), neg: int(neg), p_value: float(p_value)}逻辑说明先计算差值并剔除 0 值然后统计正负个数取较小者作为 k最后用二项分布的累积分布函数算出双侧 p 值。scipy.stats.binom.cdf 传入 k、n、0.5 三个参数返回 P(K ≤ k)。这个函数对单样本中位数检验同样适用——只需把 median 参数设为待检验的中位数不传 y。def rank_data(x): 分配平均秩次处理并列值 order np.argsort(x) n len(x) ranks np.empty(n) i 0 while i n: j i while j n and x[order[j]] x[order[i]]: j 1 if j - i 1: ranks[order[i:j]] (i 1 j) / 2.0 else: ranks[order[i]] i 1 i j return ranks def wilcoxon_rank_sum(x, y): Wilcoxon 秩和检验 combined np.concatenate([x, y]) ranks rank_data(combined) n1, n2 len(x), len(y) R1 np.sum(ranks[:n1]) U1 R1 - n1 * (n1 1) / 2 U2 n1 * n2 - U1 mu n1 * n2 / 2.0 sigma np.sqrt(n1 * n2 * (n1 n2 1) / 12.0) z (min(U1, U2) - mu) / sigma return {R1: float(R1), U1: float(U1), U2: float(U2), z: float(z)}rank_data 函数的核心逻辑是对排序后的数据扫描遇到连续相等的值就分配平均秩。这里用 while 循环而不是 groupby是为了让处理过程对初学者透明——你能看到它一步步把并列的观测找出来再算平均。3.3 用 scipy 结果做双重验证手写函数容易在边界条件上出错所以每一步实现后都要与 scipy.stats 里久经测试的函数核对# 符号检验对照 x np.array([160, 165, 170, 168, 155, 172, 180, 162, 158, 175]) y np.array([152, 158, 165, 170, 150, 160, 171, 155, 154, 168]) manual_sign sign_test(x, y) scipy_sign stats.binomtest(manual_sign[pos], manual_sign[n], 0.5, alternativetwo-sided) print(f手写 p{manual_sign[p_value]:.4f}, scipy p{scipy_sign.pvalue:.4f}) # Wilcoxon 秩和检验对照 manual_w wilcoxon_rank_sum(group_a, group_b) scipy_w stats.mannwhitneyu(group_a, group_b, alternativetwo-sided) print(f手写 z{manual_w[z]:.4f}, scipy U{scipy_w.statistic:.1f}, p{scipy_w.pvalue:.4f})注意这里的对照逻辑手写验证主要比 U 统计量本身z 值用于正态近似的判断而 scipy 默认返回的是精确 p 值。当样本量较小时两者可能略有差异——这不是谁算错了而是精确分布和近似分布的区别。考试或报告中以题目要求的检验方式为准查表题写临界值结论软件题写精确 p 值。4. 多组比较与秩相关Kruskal-Wallis 和 Spearman 的计算要点4.1 Kruskal-Wallis 的 H 统计量秩和平方的加权公式当组数从 2 增加到 3 组及以上时Wilcoxon 秩和检验不能再直接用否则会引入多重比较带来的 I 类错误膨胀。Kruskal-Wallis 检验是 Wilcoxon 秩和检验向多组情形的推广把所有组的观测合并排序、分配秩次然后比较各组的平均秩。H 统计量的计算公式为H [12 / (N(N1))] × Σ(Rᵢ² / nᵢ) - 3(N1)其中 Rᵢ 是第 i 组的秩和nᵢ 是第 i 组的样本量N 是总样本量。H 在零假设下近似服从自由度为 k-1 的卡方分布k 为组数。这个近似在每组样本量不小于 5 时效果较好如果某组样本量太小需要用精确分布计算。以三组数据为例组观测值秩次秩和 RᵢnᵢG110, 14, 152, 6, 7153G212, 13, 184, 5, 9183G39, 11, 161, 3, 8123先合并排序9(G3)、10(G1)、11(G3)、12(G2)、13(G2)、14(G1)、15(G1)、16(G3)、18(G2)对应的秩次为 1 到 9。代入公式H [12 / (9 × 10)] × [(15²/3) (18²/3) (12²/3)] - 3 × 10 (12/90) × (75 108 48) - 30 0.8自由度 df 3 - 1 2查卡方分布表p 值约为 0.67远大于 0.05不拒绝“三组分布相同”的原假设。手算时最容易错的是中间那一步15²/3、18²/3、12²/3 分别算再求和最后乘 12/(N(N1))——顺序不能乱先算括号里的 Σ(Rᵢ²/nᵢ)再乘系数最后减去 3(N1)。提示如果三组数据存在大量并列值H 统计量需要除以校正因子 1 - Σ(t_j³ - t_j) / (N³ - N)其中 t_j 是每个并列组的大小。手算题一般会明确说“无并列值”或数据量很小这时不用校正但用软件算时校正默认开启遇到手算与软件不一致先检查是不是这个原因。4.2 Spearman 秩相关的两种等价算法Spearman 秩相关系数衡量两个变量之间的单调关系强度。它的手算有三种路径掌握前两种就足够应付大多数题目。第一种是经典差值公式ρ 1 - 6Σdᵢ² / (n(n² - 1))其中 dᵢ 是第 i 个观测在两个变量上的秩次之差。这个公式只在“两个变量都没有并列值且秩次恰好是 1 到 n 的排列”时成立。第二种更稳健的做法是先分别对两个变量排秩然后直接计算这两列秩次的 Pearson 相关系数。两种方法在无并列值时结果完全一致有并列值时必须用第二种。from scipy.stats import rankdata def spearman_rho(x, y): Spearman 秩相关秩次的 Pearson 相关 rx rankdata(x) ry rankdata(y) rho np.corrcoef(rx, ry)[0, 1] return rho, rx, ry x np.array([85, 90, 78, 92, 88]) y np.array([75, 85, 80, 95, 82]) rho, rx, ry spearman_rho(x, y) print(fSpearman ρ {rho:.4f}) print(fX 的秩: {rx}, Y 的秩: {ry})输出结果X 的秩次为 [3, 4, 1, 5, 2]Y 的秩次为 [1, 3, 2, 5, 4]d² 41104 10套用经典公式 ρ 1 - 6×10/(5×24) 1 - 60/120 0.5。同一组数据用 scipy 的 spearmanr 函数验证也得到 0.5。关于显著性n 5 时 ρ 0.5 的 p 值约 0.45完全不显著——样本量太小时秩相关系数的波动范围非常大即使观测到 0.5 的相关也无法排除随机性。这就是为什么教材会在后面给出 Spearman 秩相关的临界值表小样本查表大样本用 t 分布近似 t ρ × √((n-2)/(1-ρ²))df n - 2。4.3 并列值太多时的分布特征与方法对比当数据中有大量并列值时所有基于秩的检验都会受影响但影响方式不同。符号检验只看方向并列值只影响是否被剔除Wilcoxon 秩和检验和 Kruskal-Wallis 检验给并列值分配平均秩相当于人为引入了分布假设以外的信息Spearman 相关对并列值的敏感度最低因为秩次差被平方后已经削弱了小偏移的影响。处理并列值的标准做法分三档如果并列值占样本比例低于 5%平均秩法和随机打破并列法结果差异可以忽略比例在 5% 到 20% 之间使用平均秩法并按校正公式调整统计量超过 20%秩方法本身的适用性就存疑了应该考虑更稳健的推断方法或改用 Bootstrap 置信区间。5. 验证计算答案的三种手段模拟、双查与效应量课后计算题做完之后只对照一次答案往往不够因为秩方法的手算环节多、中间变量多任何一步出错都会让结论反转。我一般会用三种手段交叉验证。第一种是随机模拟验证。对于手算得到的 p 值构造相同样本量和分布的数据重复抽样 10000 次看实际观测到的检验统计量在模拟分布中的位置。这个方法的成本低、信息量大# 模拟验证用置换检验核对 Wilcoxon 秩和检验 rng np.random.default_rng(42) n1, n2 6, 5 combined np.concatenate([group_a, group_b]) obs_U stats.mannwhitneyu(group_a, group_b).statistic perm_count 0 for _ in range(10000): perm rng.permutation(combined) perm_a perm[:n1] perm_b perm[n1:] perm_U stats.mannwhitneyu(perm_a, perm_b).statistic if perm_U obs_U: perm_count 1 p_perm 2 * perm_count / 10000 # 双侧近似 print(f置换检验 p {p_perm:.4f})置换检验的逻辑是原假设成立时组标签不影响分布所以随机打乱组标签得到的统计量应该和观测值同分布。如果观测到的 U 落到置换分布的尾部说明组间差异不像随机分配能产生的。这种方法几乎不做任何分布假设是验证手算结果最可靠的参照。第二种是查表双确认。很多教材的附表只给双侧 0.05 和 0.01 两个水平但考试可能要求 0.1 或单侧结论。这时手算的 p 值落在哪个区间比具体数值更重要。建议把所有检验的区间判断统一记在题号旁边拒绝、不拒绝、边界p 值在 0.05 附近且无法精确判断避免最后汇总时混淆。第三种是补充计算效应量。秩检验的 p 值受样本量影响很大大样本下即使组间差异很小p 值也可能很小。课后题通常不会要求效应量但当你把同样的检验应用到真实数据时需要至少算一个概率优势指标# 计算 Wilcoxon 检验的效应量 r Z / sqrt(N) z_stat stats.norm.ppf(stats.mannwhitneyu(group_a, group_b).pvalue / 2) r_effect abs(z_stat) / np.sqrt(len(group_a) len(group_b)) print(f效应量 r {r_effect:.3f})效应量在 0.3 以上才算有实际意义p 值只告诉你“有没有差异”效应量告诉你“差异有多大”。把这三个指标写在同一处比单独一个 p 值更有说服力也正好对应教材里“统计显著”与“实际显著”的区别。查表题可以不写效应量但如果你用软件算课后题顺手补上这个值对理解秩检验的性质会更有帮助。本文还有配套的精品资源点击获取