news 2026/10/2 17:40:18

Shapiro-Wilk与Shapiro-Francia正态性检验选型指南:原理、代码与避坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Shapiro-Wilk与Shapiro-Francia正态性检验选型指南:原理、代码与避坑

简介:这份资源聚焦复合正态性检验,面向需要做参数假设检验的数据分析人员、统计学习者与科研工作者,解决样本正态性判断这一常见前置问题。核心实现 Shapiro-Wilk 检验,支持样本量 3≤n≤5000,基于 Royston R94 算法,并对 platykurtic 样本额外执行 Shapiro-Francia 正态性检验,兼顾不同分布形态下的判断需求。压缩包为 zip 格式,仅含 1 个 m 文件,体积约 3KB,属于轻量级脚本工具,便于直接嵌入现有 MATLAB 分析流程调用。目前已有 946 人学习下载,说明其在统计检验场景中具有一定参考价值。读者可获得一套可直接运行的检验脚本,理解两种检验的适用边界与算法实现思路,并借助样本量范围设定快速完成批量数据的正态性筛查,为后续 t 检验、方差分析等方法的选择提供依据。

1. 正态性检验选谁:Shapiro-Wilk 和 Shapiro-Francia 到底差在哪

做数据预处理时,很多人会顺手跑一个shapiro.test(),看到 p 值大于 0.05 就松一口气,觉得数据“正态了”,然后放心去做 t 检验或线性回归。但真正踩过坑的人知道,正态性检验不是一道是非题,而是一组权衡:样本量多大、尾部有多重、有没有并列值,都会让 Shapiro-Wilk 和 Shapiro-Francia 给出不一样的结论。这两个检验名字很像,都带 Shapiro,核心思路也一脉相承——把排序后的样本和正态分布的理论分位数做回归,看拟合得有多直。区别在于它们对“直”的度量方式不同,导致在小样本、重尾、并列值场景下表现分化。这篇文章面向需要做正态性判断的从业者:无论你是做 A/B 实验、金融收益率建模还是传感器数据清洗,只要涉及“这组数能不能当正态处理”,Shapiro-Wilk 和 Shapiro-Francia 就是绕不开的两个工具。我会把选型理由、手算逻辑、代码复现和踩坑记录一次讲透,让你下次看到 p 值时心里有底,而不是被一个数字牵着走。

2. 两个检验的底层逻辑:为什么它们比 K-S 检验更值得用

2.1 从“排序后回归”理解检验统计量

Shapiro-Wilk 和 Shapiro-Francia 都属于基于次序统计量的正态性检验。把样本从小到大排列成 $x_{(1)} \le x_{(2)} \le \dots \le x_{(n)}$,正态分布的理论分位数记作 $m_i = \Phi^{-1}((i - 0.375)/(n + 0.25))$,这是 Blom 近似,也是常见实现里的默认做法。如果样本真的来自正态分布,那么 $x_{(i)}$ 和 $m_i$ 应该近似落在一条直线上。两个检验都在度量这条直线的“直度”,但用的统计量不同。

Shapiro-Wilk 的统计量是:

$$ W = \frac{\left(\sum_{i=1}^{n} a_i x_{(i)}\right)^2}{\sum_{i=1}^{n} (x_i - \bar{x})^2} $$

其中 $a_i$ 是一组由样本量和正态分布协方差矩阵推导出来的权重,分子是“最优线性组合”的平方,分母是总平方和。$W$ 越接近 1,越像正态。Shapiro-Francia 则更直接,它用平方相关系数:

$$ W' = \frac{\left(\sum_{i=1}^{n} (m_i - \bar{m})(x_{(i)} - \bar{x})\right)^2}{\sum_{i=1}^{n}(m_i - \bar{m})^2 \sum_{i=1}^{n}(x_{(i)} - \bar{x})^2} $$

也就是排序样本和理论分位数的 Pearson 相关系数的平方。$W'$ 同样越接近 1 越正态。区别在于,Shapiro-Wilk 的权重 $a_i$ 是经过优化的,对尾部更敏感;Shapiro-Francia 直接用分位数做相关,计算更简单,但在小样本下对尾部偏离的敏感度略低。

提示:很多教材把这两个检验混为一谈,实际上它们的零分布不同,p 值不能互换使用。

2.2 为什么不用 Kolmogorov-Smirnov 或 Anderson-Darling

K-S 检验比较的是经验分布函数和理论分布函数的最大距离,它对分布中心敏感,但对尾部不敏感。而正态性检验最怕的就是尾部出问题——金融收益率、传感器噪声、用户行为间隔,往往都是尾部偏重。Shapiro 系列检验专门针对正态分布设计,功效更高。Anderson-Darling 虽然也对尾部敏感,但它的临界值依赖分布假设,实现起来更麻烦。所以在“只判断正态性”这个任务上,Shapiro-Wilk 和 Shapiro-Francia 是更专注的工具。

另一个现实原因是:R 的shapiro.test()默认就是 Shapiro-Wilk,Python 的scipy.stats.shapiro也是。Shapiro-Francia 在 R 里需要shapiro.test的变体或nortest包,Python 里没有直接内置,但可以自己实现。下面我会给出两种语言的复现代码。

2.3 样本量边界:3 到 5000 的硬约束

Shapiro-Wilk 原始版本要求样本量在 3 到 5000 之间。超过 5000 时,R 会报错 “sample size must be between 3 and 5000”。这不是随便定的,而是因为 $a_i$ 权重表在 n 很大时计算不稳定,而且大样本下任何微小偏离都会导致拒绝。Shapiro-Francia 的适用范围更宽,理论上可以到几千,但同样不建议超过 5000,因为大样本下 p 值会变得过于敏感。

实际工作中,如果样本量超过 5000,常见做法是随机抽样到 5000 以内,或者改用偏度-峰度检验、Anderson-Darling。但要注意:大样本下正态性检验几乎总是拒绝,因为真实数据很难完美正态。这时候更应该看效应量,比如偏度和峰度的绝对值,而不是死磕 p 值。

3. 用 Python 和 R 跑通两个检验:最小命令与参数说明

3.1 Python 实现 Shapiro-Wilk 与手写 Shapiro-Francia

Python 的scipy.stats.shapiro直接给出 W 和 p 值。Shapiro-Francia 需要自己算,下面是一个完整可复现的脚本。

import numpy as np from scipy import stats # 生成一组模拟数据:正态 + 轻微右偏 np.random.seed(42) normal_data = np.random.normal(loc=10, scale=2, size=50) skewed_data = np.random.exponential(scale=2, size=50) + 5 def shapiro_francia(x): """ 计算 Shapiro-Francia 的 W' 和 p 值(p 值用近似公式) x: 一维数组 返回: (W_prime, p_value) """ x = np.sort(x) n = len(x) # Blom 近似理论分位数 m = stats.norm.ppf((np.arange(1, n+1) - 0.375) / (n + 0.25)) m_bar = np.mean(m) x_bar = np.mean(x) # 分子:协方差的平方 numerator = (np.sum((m - m_bar) * (x - x_bar))) ** 2 # 分母:两个平方和的乘积 denominator = np.sum((m - m_bar)**2) * np.sum((x - x_bar)**2) W_prime = numerator / denominator # p 值近似:基于 Royston 1993 的变换,这里用简化版 # 实际使用时建议查表或使用专门包 # 这里仅作演示,p 值用正态近似 z = (W_prime - 0.98) / 0.02 # 粗略近似,不精确 p_value = 2 * (1 - stats.norm.cdf(abs(z))) return W_prime, p_value # Shapiro-Wilk W, p = stats.shapiro(normal_data) print(f"正态数据 Shapiro-Wilk: W={W:.4f}, p={p:.4f}") W2, p2 = stats.shapiro(skewed_data) print(f"偏态数据 Shapiro-Wilk: W={W2:.4f}, p={p2:.4f}") # Shapiro-Francia Wf, pf = shapiro_francia(normal_data) print(f"正态数据 Shapiro-Francia: W'={Wf:.4f}, p={pf:.4f}") Wf2, pf2 = shapiro_francia(skewed_data) print(f"偏态数据 Shapiro-Francia: W'={Wf2:.4f}, p={pf2:.4f}")

这段代码的逻辑说明:shapiro_francia函数先对数据排序,然后计算 Blom 近似分位数m。分子是m和x的协方差平方,分母是两者平方和的乘积,得到 $W'$。p 值部分我用了非常粗略的正态近似,实际生产中不要用这个 p 值,应该查 Royston 1993 的表格或使用scipy.stats.shapiro的 p 值作为参考。参数方面,np.random.seed(42)保证可复现;size=50是样本量,你可以改成 20、100、500 观察变化。

运行结果会显示:正态数据的 W 接近 0.98,p 值大于 0.05;偏态数据的 W 明显更低,p 值小于 0.05。Shapiro-Francia 的 $W'$ 趋势类似,但数值略有不同。

3.2 R 语言:shapiro.test与nortest包

R 里 Shapiro-Wilk 是内置的,Shapiro-Francia 在nortest包里叫sf.test。

# 安装 nortest 包(如果还没装) # install.packages("nortest") library(nortest) set.seed(42) normal_data <- rnorm(50, mean = 10, sd = 2) skewed_data <- rexp(50, rate = 0.5) + 5 # Shapiro-Wilk sw_normal <- shapiro.test(normal_data) sw_skewed <- shapiro.test(skewed_data) print(sw_normal) print(sw_skewed) # Shapiro-Francia sf_normal <- sf.test(normal_data) sf_skewed <- sf.test(skewed_data) print(sf_normal) print(sf_skewed)

shapiro.test返回 W 和 p 值,sf.test返回 W' 和 p 值。注意sf.test的样本量限制也是 3 到 5000。参数上,shapiro.test没有额外参数,sf.test也没有。如果你要批量检验多个列,可以用apply或purrr::map。

注意:R 的shapiro.test在样本量小于 3 时会报错,大于 5000 也会报错。sf.test同样。

3.3 参数怎么设:显著性水平、样本量与重复检验

显著性水平 $\alpha$ 默认 0.05,但在多重检验场景下需要校正。比如你对 20 个特征分别做正态性检验,至少有一个假阳性的概率是 $1 - 0.95^{20} \approx 0.64$。这时候应该用 Bonferroni 校正($\alpha/20$)或 FDR。样本量方面,如果 n < 20,检验功效很低,即使数据不正态也可能不拒绝;如果 n > 5000,几乎总是拒绝。所以我的习惯是:n < 20 时看 Q-Q 图为主,n 在 20 到 5000 之间用 Shapiro-Wilk,n > 5000 时抽样或看偏度峰度。

4. 避坑与排查:正态性检验的 5 个血泪教训

4.1 现象:p 值刚好在 0.05 附近,结论反复横跳

原因:Shapiro-Wilk 的 p 值在 0.05 附近对样本量极其敏感。增加或减少几个样本,p 值可能从 0.048 跳到 0.052。这不是 bug,而是检验本身的特性。

解决:不要只看 p 值。同时报告 W 统计量和 Q-Q 图。如果 W 在 0.98 以上,即使 p 值略小于 0.05,也可以认为近似正态。如果 W 低于 0.95,即使 p 值大于 0.05,也要警惕。

4.2 现象:数据有大量并列值,Shapiro-Wilk 报错或结果异常

原因:Shapiro-Wilk 假设连续分布,并列值会破坏次序统计量的独立性。比如问卷的 1-5 分李克特量表,大量重复值会导致 W 被高估,p 值偏大。

解决:对并列值多的数据,改用 Shapiro-Francia 或 Anderson-Darling。或者先做 ties 校正。R 的shapiro.test在并列值多时会给出警告 “ties should not be present”。

4.3 现象:样本量 5001,R 直接报错

原因:shapiro.test硬编码了 3 到 5000 的限制。

解决:随机抽样到 5000 以内,或者改用nortest::ad.test(Anderson-Darling)或moments::agostino.test(偏度检验)。抽样时用set.seed保证可复现。

4.4 现象:Shapiro-Wilk 和 Shapiro-Francia 结论相反

原因:两个检验对尾部的敏感度不同。Shapiro-Wilk 对尾部更敏感,Shapiro-Francia 对中心更敏感。如果数据尾部有离群值但中心很直,Shapiro-Wilk 会拒绝,Shapiro-Francia 可能不拒绝。

解决:结合 Q-Q 图判断。如果 Q-Q 图两端偏离但中间直,说明尾部有问题,这时候用稳健统计方法或考虑 t 检验的替代方案(如 Wilcoxon)。

4.5 现象:对残差做正态性检验,p 值很大,但模型预测很差

原因:正态性检验只检查残差分布是否正态,不检查线性、同方差、独立性。残差正态但模型欠拟合的情况很常见。

解决:正态性检验只是回归诊断的一环。还要看残差-拟合值图、Scale-Location 图、Durbin-Watson 检验。不要因为残差正态就认为模型没问题。

5. 进阶技巧:用模拟评估检验功效与样本量规划

5.1 用 Monte Carlo 模拟比较两个检验的功效

想知道在特定样本量和偏离程度下,哪个检验更容易检出非正态?可以跑一个简单的模拟。

import numpy as np from scipy import stats def power_comparison(n, n_sim=1000, alpha=0.05): """ 比较 Shapiro-Wilk 和 Shapiro-Francia 在指数分布下的功效 n: 样本量 n_sim: 模拟次数 alpha: 显著性水平 """ sw_reject = 0 sf_reject = 0 for _ in range(n_sim): # 指数分布(明显非正态) data = np.random.exponential(scale=1.0, size=n) # Shapiro-Wilk _, p_sw = stats.shapiro(data) if p_sw < alpha: sw_reject += 1 # Shapiro-Francia(用前面的函数) _, p_sf = shapiro_francia(data) if p_sf < alpha: sf_reject += 1 return sw_reject / n_sim, sf_reject / n_sim for n in [10, 20, 50, 100]: sw_power, sf_power = power_comparison(n) print(f"n={n}: Shapiro-Wilk 功效={sw_power:.3f}, Shapiro-Francia 功效={sf_power:.3f}")

这段代码模拟指数分布数据,重复 1000 次,计算两个检验拒绝原假设的比例。参数n_sim越大越稳定,但耗时越长。alpha是显著性水平。运行后你会看到:小样本(n=10)时两者功效都低;n=50 时 Shapiro-Wilk 略高;n=100 时两者都接近 1。这能帮你判断在给定样本量下,检验是否能可靠检出非正态。

5.2 样本量规划:需要多少数据才能检出偏离

反过来,如果你希望以 80% 的功效检出某种程度的偏离,需要多大样本?可以用模拟反推。常见做法是设定效应量(比如偏度 0.5),然后逐步增加 n,直到功效达到 0.8。这个模拟比查表更灵活,因为你可以针对自己的数据分布做。

5.3 一个实用习惯:永远画 Q-Q 图

我做了这么多年数据,最深的教训就是:不要只信 p 值。p 值告诉你“是否偏离”,但不告诉你“偏离多大”和“偏离在哪”。Q-Q 图能直接看到尾部、中心、离群点。我的习惯是:先画 Q-Q 图,再跑 Shapiro-Wilk,如果两者矛盾,以 Q-Q 图为准。如果 Q-Q 图显示尾部有问题,我会考虑用稳健方法或数据变换,而不是硬做正态假设。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 17:39:37

DCG下Multi-bit FF物理优化全解析:降低时钟功耗的实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 17:38:44

动态内存管理(c++方向必看)

引言&#xff1a; 学 C 的时候&#xff0c;我一度觉得 malloc 挺多余——数组不是挺好用吗&#xff1f; 直到写了个小练习&#xff1a;让用户输入一串数字再排序。写完发现卡住了&#xff0c;数组长度写多少&#xff1f;写 10&#xff0c;用户输入 11 个就崩&#xff1b;写 100…

作者头像 李华
网站建设 2026/10/2 17:38:09

设计模式考试能力训练系统:从题干解码到架构决策

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 17:37:31

BCM、EPS、SAS、VCU实战解析:从物理形态到故障诊断

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 17:31:47

免费智能大纲能用什么付费才能买什么

挑写作平台的人多半先落到价格页&#xff0c;看到「免费」二字就注册&#xff0c;真正用起来才发现能做和不能做的部分差别不小。与其纠结谁的价格低&#xff0c;不如把免费智能大纲能免费用到什么程度、付费之后换来哪些能力这两件事拆开看清。知学术AIPaperGPT在这条界线上写…

作者头像 李华