决策表
先确定结局变量类型和研究设计,再看分布。表中“首选”是多数医学期刊审稿时认可的做法,“备选”是条件不满足或想做敏感性分析时的方法。
“独立”与“配对”按数据产生方式判断。同一只动物左右两侧、同一患者治疗前后、按年龄性别 1:1 匹配的病例和对照,都属于配对数据。同一患者的多个病灶、多颗牙齿、多次随访,也不是独立观测,分析单位要与随机化或抽样单位一致。
有序等级资料(如疗效分为治愈、显效、有效、无效)比较两组时用 Mann-Whitney U 检验,用卡方检验会丢掉等级顺序信息。
| 研究问题 | 结局变量 | 设计 | 首选方法 | 备选方法与使用条件 | 报告的效应量 |
|---|---|---|---|---|---|
| 两组均数比较 | 连续 | 两组独立 | Welch t 检验 | 两组样本量和方差都接近时 Student t 与 Welch t 结果几乎相同;明显偏态且每组少于约 30 例用 Mann-Whitney U | 均数差及 95% CI,Hedges g |
| 两组分布比较 | 连续偏态或有序等级 | 两组独立 | Mann-Whitney U 检验(Wilcoxon 秩和检验) | 右偏的浓度、费用类数据可对数变换后用 Welch t,结果解释为几何均数之比 | Hodges-Lehmann 位置差及 95% CI,秩二列相关 |
| 前后或配对比较 | 连续 | 配对(同一对象或配对对象) | 配对 t 检验 | 差值明显偏态时用 Wilcoxon 符号秩检验 | 差值均数及 95% CI,dz |
| 三组及以上均数比较 | 连续 | 多组独立 | 单因素方差分析 + Tukey 检验 | 方差不齐用 Welch 方差分析 + Games-Howell;只与对照组比较用 Dunnett | η² 或 ω²,两两差值及 95% CI |
| 三组及以上分布比较 | 连续偏态或有序等级 | 多组独立 | Kruskal-Wallis 检验 + Dunn 检验(Holm 或 Bonferroni 校正) | 有序等级资料也可用有序 Logistic 回归 | ε² 或 η²H |
| 多个时间点比较 | 连续 | 同一对象重复测量 | 重复测量方差分析,报告 Mauchly 球形检验并用 Greenhouse-Geisser 校正 | 有缺失时间点或时间间隔不等时用线性混合模型;偏态时用 Friedman 检验 | 广义 η²,各时间点均数及 95% CI |
| 两个因素的作用 | 连续 | 析因设计 | 两因素方差分析(含交互项,III 型平方和) | 不平衡设计必须写明平方和类型,见软件对照一节 | 偏 η²,简单效应 |
| 两组或多组率比较 | 二分类或无序多分类 | 独立 | Pearson 卡方检验 | 四格表期望频数小于 5 或总例数小于 40 时用 Fisher 精确检验;R×C 表超过 1/5 格子期望频数小于 5 时用 Fisher-Freeman-Halton 精确检验 | 率差、RR 或 OR 及 95% CI |
| 配对的二分类比较 | 二分类 | 同一对象两种方法或前后 | McNemar 检验 | 不一致对数 b+c 较小时用精确二项检验 | 不一致比例之差或配对 OR |
| 两个连续变量的关联 | 连续 | 同一对象两个变量 | Pearson 相关(线性、无明显离群值) | 偏态、有序或有离群值时用 Spearman 相关;每人多次测量不能直接合并计算 | r 及 95% CI |
| 两种测量方法的一致性 | 连续 | 同一对象两种方法 | Bland-Altman 一致性界限 | 组内相关系数(ICC);不用相关系数判断一致性 | 平均差值及 95% 一致性界限 |
| 多因素调整 | 连续 | 任意 | 线性回归 | 结局右偏时对数变换或用广义线性模型 | 回归系数及 95% CI,R² |
| 多因素调整 | 二分类 | 任意 | Logistic 回归 | 结局常见(超过约 10%)时 OR 会夸大 RR,可用对数二项或修正 Poisson 回归报告 RR | OR 及 95% CI |
| 生存时间 | 时间 + 是否发生事件(有删失) | 任意 | Kaplan-Meier 曲线 + log-rank 检验;多因素用 Cox 回归 | 比例风险假定不成立时用分段或时间依存协变量 | HR 及 95% CI,中位生存时间 |
前提条件
t 检验和方差分析要求的是每组内(或回归残差)近似正态,不要求把全部数据合在一起后正态。大样本时它们对非正态相当稳健,方差不等和样本量不等同时出现才是主要风险。
正态性检验对样本量的敏感性(本页实测)
从自由度为 10 的 t 分布(只有轻度厚尾)抽样,set.seed(2026):n=30 时 Shapiro-Wilk P=0.60,n=100 时 P=0.42,n=1000 时 P=0.0019,n=5000 时 P=8.6×10⁻¹²。重复 200 次,n=30 时只有 12% 的样本被判为非正态,n=5000 时 100% 被判为非正态。同一种分布,结论只随样本量变化。
偏度与峰度的判断阈值
Kim(2013,Restor Dent Endod)给出:n<50 时偏度或峰度的 z 值绝对值大于 1.96 判为非正态;50≤n<300 时阈值为 3.29;n≥300 时不看 z 值,看直方图以及偏度绝对值是否大于 2、峰度绝对值是否大于 7。Shapiro-Wilk 与 K-S 检验适合 n<300 的样本。
多大样本可以不管正态性
Lumley 等(2002,Annu Rev Public Health)回顾模拟研究后指出,t 检验和线性回归所需的“足够大”样本常在 100 以内,即使是极端偏态的医疗费用数据也小于 500。前提是方差不能相差太大,或者用不依赖等方差的 Welch t 检验和稳健标准误。
Levene 检验的不同版本
R 的 car::leveneTest 和 SciPy 的 stats.levene 默认以中位数为中心(即 Brown-Forsythe 检验),SPSS 独立样本 t 检验输出的是以均数为中心的经典 Levene 检验。本页实测 airquality 5 月与 8 月臭氧数据:中位数版 F=9.50,P=0.0033;均数版 F=10.09,P=0.0026。与 SPSS 对数时,在 R 中加 center = mean。
| 常见做法 | 问题 | 建议做法 |
|---|---|---|
| 每个变量都先做 Shapiro-Wilk,P<0.05 就换非参数检验 | 样本大时微小偏离也会 P<0.05,样本小时严重偏离也检验不出来 | 看 Q-Q 图和直方图,结合偏度、峰度判断;大样本直接用 t 检验或方差分析 |
| 先做 Levene 检验,P>0.05 用 Student t,否则用 Welch t | 两阶段选择本身会改变 I 类错误率;Levene 检验在小样本下功效低 | 直接用 Welch t。方差相等时它损失的功效很小,方差不等时它的 I 类错误率更接近名义水平 |
| 用本次数据的正态性检验结果决定用 t 检验还是秩和检验 | Rochon 等 2012 年的模拟认为这种两阶段做法在形式上不正确 | 按既往研究、预试验或变量性质事先决定;不确定时直接用非参数检验 |
| 把 Mann-Whitney U 检验的结果写成“两组中位数不同” | 两组分布形状或离散程度不同时,检验显著不等于中位数不同(Hart 2001) | 报告各组中位数和四分位数,用 Hodges-Lehmann 位置差描述差异 |
实测:两组比较
本页实测:R 4.4.3(car 3.1.5、effectsize 1.0.3、rstatix 1.1.0、afex 1.5.1、survival 3.8.12),Python 3.12(SciPy 1.18.1、statsmodels 0.15.0、pingouin 0.7.0、lifelines 0.30.3),macOS arm64;数据为 R 内置数据集,导出为 CSV 后两边读取同一份数据。数据为 airquality 中的臭氧浓度(ppb),右偏且两个月份方差相差较大。
6 月 vs 8 月这一行中,样本量大的一组方差也大,Student t 把两组方差合并后偏向大组,标准误被高估,P 值偏大(0.034 对 0.0043)。反过来,如果样本量小的一组方差更大,Student t 的 P 值会偏小,假阳性增加。Welch t 在两种情况下都不需要事先判断。
效应量与置信区间:5 月 vs 8 月均数差 −36.3 ppb(Welch 95% CI −54.4 至 −18.3),Hedges g=−1.11(95% CI −1.69 至 −0.53);6 月 vs 8 月均数差 −30.5 ppb(95% CI −50.7 至 −10.4),用不合并 SD 计算的 Hedges g=−0.96(95% CI −1.61 至 −0.30)。
配对数据误当独立样本:sleep 数据集是 10 名受试者分别服用两种药物后的睡眠增加时长。配对 t 检验 t=4.06,df=9,P=0.0028,差值均数 1.58 小时(95% CI 0.70 至 2.46);按两独立样本做 t 检验 t=1.86,df=18,P=0.079。个体间差异没有被扣除,原本明确的差异就检验不出来。
| 比较 | 各组 n、均数(SD) | Student t | Welch t | Mann-Whitney U | R 与 Python 是否一致 |
|---|---|---|---|---|---|
| 5 月 vs 8 月(样本量相等) | 26,23.6(22.2);26,60.0(39.7) | t=−4.075,df=50,P=0.000165 | t=−4.075,df=39.3,P=0.000217 | W=127.5,P=0.000121 | 一致(scipy、pingouin 结果到小数点后 6 位相同) |
| 6 月 vs 8 月(样本量不等) | 9,29.4(18.2);26,60.0(39.7) | t=−2.211,df=33,P=0.034 | t=−3.092,df=30.0,P=0.0043 | W=57.5,P=0.026 | 一致 |
多组与重复测量
整体检验回答“各组是否全部相同”,事后检验回答“哪两组不同”。两者都要报告。
ctrl 与 trt2 的比较说明了两两 t 检验的问题:不校正时 P=0.048,按 0.05 会写成“有统计学差异”;Tukey 校正后 P=0.198。三组只做 3 次比较,组数为 5 时要做 10 次比较,膨胀更明显。
Kruskal-Wallis(airquality 5 至 9 月臭氧,n=116):H=29.27,df=4,P=6.9×10⁻⁶,η²H=0.23。事后用 Dunn 检验加 Holm 校正,5 月 vs 7 月、5 月 vs 8 月、7 月 vs 9 月、8 月 vs 9 月有差异。不要在 Kruskal-Wallis 之后用两两 Mann-Whitney 检验且不校正。
重复测量(Indometh,6 名受试者在 0.5、1、2、4、8 小时的吲哚美辛血药浓度):Mauchly 检验 W=0.00063,P=0.0059,球形假定不成立;未校正 F(4, 20)=106.6,Greenhouse-Geisser ε=0.378,校正后自由度为 1.51 和 7.55,P=4.7×10⁻⁶。R 的 afex::aov_ez 与 pingouin.rm_anova 结果一致。Friedman 检验 χ²=24.0,P=8.0×10⁻⁵。论文中写明用的是哪种校正以及 ε 值。
| 方法(PlantGrowth,3 组各 10 株) | ctrl vs trt1 | ctrl vs trt2 | trt1 vs trt2 |
|---|---|---|---|
| 两两 Welch t 检验,不校正(错误做法) | P=0.250 | P=0.048 | P=0.009 |
| 两两 Welch t 检验 + Holm 校正 | P=0.250 | P=0.096 | P=0.028 |
| Tukey HSD(方差齐时首选) | P=0.391 | P=0.198 | P=0.012 |
| Games-Howell(方差不齐时) | P=0.475 | P=0.113 | P=0.024 |
- Tukey 检验可用于各组例数不等的情况(Tukey-Kramer 法),R 的 TukeyHSD 与 SPSS 的 Tukey 都会自动处理。
- 只关心各处理组与同一个对照组的比较时,用 Dunnett 检验,比较次数少,功效高于 Tukey。
- LSD 法只在恰好 3 组且整体 F 检验显著时能控制族错误率,组数更多时不要用。
- SNK 法在部分零假设成立时不能控制族错误率,期刊审稿常要求改用 Tukey 或 Holm。
- 重复测量数据有失访时,重复测量方差分析会删除整个受试者;线性混合模型可以利用不完整的观测。
多重比较
10 个相互独立且零假设都成立的检验,至少一个 P<0.05 的概率是 1−0.95¹⁰=40%。校正方法的选择取决于比较的结构和研究性质。
这组 P 值中原始 P<0.05 的有 6 个;Bonferroni 和 Holm 校正后只剩第 1 个,BH 校正后剩前 3 个。论文中写明校正方法和校正的检验族(例如“对 3 个次要结局的 6 次组间比较用 Holm 法校正”),并报告校正后的 P 值或校正后的显著性水准。
原始 P Bonferroni Holm BH(FDR)
0.001 0.010 0.010 0.0100
0.008 0.080 0.072 0.0400
0.012 0.120 0.096 0.0400
0.021 0.210 0.147 0.0525
0.035 0.350 0.210 0.0700
0.048 0.480 0.240 0.0800
0.090 0.900 0.360 0.1286
0.200 1.000 0.600 0.2500
0.410 1.000 0.820 0.4556
0.740 1.000 0.820 0.7400| 情形 | 方法 | 说明 |
|---|---|---|
| 方差分析后所有两两比较 | Tukey(方差不齐用 Games-Howell) | 利用全部组的误差估计,比对每对比较单独校正的功效高 |
| 各组只与一个对照组比较 | Dunnett | 比较次数为组数减 1 |
| 少量预先计划的比较,或不同类型检验的组合 | Holm | 控制族错误率,功效不低于 Bonferroni,且不需要额外假设,可直接替代 Bonferroni |
| 数十个以上指标、基因、影像区域的探索性筛选 | Benjamini-Hochberg(FDR) | 控制的是阳性结果中假阳性的比例,结果需在独立数据中验证 |
| 确证性研究的主要结局只有一个 | 不校正 | 在方案或统计分析计划中预先指定 |
| 探索性分析、次要结局 | 可不校正,但明确标注为探索性 | Bender 与 Lange(2001)的建议;NEJM 2019 年的统计指南要求未预先规定校正方法的次要结局只报告效应估计和 95% CI |
分类变量
四格表先看总例数和最小期望频数,再选检验。R 的 chisq.test 和 SciPy 的 chi2_contingency 对四格表默认都加 Yates 连续性校正,SPSS 同时输出未校正和校正两行。
国内医学统计教材的四格表规则是:n≥40 且所有期望频数 T≥5,用 Pearson 卡方;n≥40 且有 1≤T<5,用连续性校正卡方;n<40 或有 T<1,用 Fisher 精确检验。R×C 表要求没有 T<1 的格子,且 1≤T<5 的格子不超过 1/5。
Campbell(2007,Stat Med)的模拟比较认为 Yates 校正过于保守,建议所有期望频数不小于 1 时用 N−1 卡方(Pearson χ² 乘以 (N−1)/N),否则用 Fisher 检验。投稿国内期刊按教材规则写即可;投国际期刊时可直接报告 Fisher 精确检验或未校正卡方,并写明理由。
Fisher 检验报告 OR 时,R 给出的是条件最大似然估计,SciPy 给出的是 ad/bc 样本 OR,小样本时两者相差明显(8.15 对 9.33)。论文中报告 OR 及其 95% CI 时写明计算方法,或者统一用 Logistic 回归估计。
McNemar 检验(R 帮助文档中的 1600 人两次民意调查数据,不一致对 b=150、c=86):连续性校正 χ²=16.82,P=4.1×10⁻⁵;未校正 χ²=17.36,P=3.1×10⁻⁵;对不一致对做精确二项检验 P=3.7×10⁻⁵。R 的 mcnemar.test 默认加校正,statsmodels 的 mcnemar 默认 exact=True,两者默认结果不同。
| 数据(本页实测) | Pearson χ²(未校正) | Yates 校正 χ² | Fisher 精确检验 | OR 估计 |
|---|---|---|---|---|
| infert:自然流产史 × 病例/对照(n=248,最小期望频数 35.8) | χ²=27.18,P=1.8×10⁻⁷ | χ²=25.79,P=3.8×10⁻⁷ | P=3.5×10⁻⁷ | R fisher.test 条件最大似然 OR=4.24(95% CI 2.35 至 7.80);scipy fisher_exact 样本 OR=4.27 |
| 人工小样本 [[7,3],[2,8]](n=20,期望频数 4.5 和 5.5) | — | χ²=3.23,P=0.072;R 警告 Chi-squared approximation may be incorrect | P=0.070 | R 条件 OR=8.15;scipy 样本 OR=9.33 |
相关与回归
相关系数描述线性或单调关联的强度,回归系数描述调整其他变量后的效应大小,两者都不能单独支持因果结论。
Logistic 与 Cox 回归的变量数受事件数限制。Peduzzi 等(1996)的模拟研究提出每个自变量至少 10 个事件(EPV≥10);后续研究认为这只是粗略下限,预测模型的样本量应按 Riley 等的方法计算。事件只有 30 个时放入 10 个自变量,系数估计会严重偏倚。
Pearson 与 Spearman(本页实测)
airquality 臭氧与气温(n=116):Pearson r=0.698(95% CI 0.591 至 0.781),Spearman ρ=0.774。臭氧右偏,两者差距说明关系是单调但非线性的。R 的 cor.test 对 Spearman 有结时会警告 Cannot compute exact p-value with ties,加 exact = FALSE 用近似法即可。
相关不等于一致
比较两种测量方法时,两种方法的读数可能高度相关却存在系统偏差。Bland 与 Altman(1986,Lancet)指出用相关系数评价一致性会误导,应计算两法差值的均数和 95% 一致性界限(均数 ±1.96 SD)。
每人多次测量不能直接合并
同一受试者多次测量的数据点直接合并计算相关,样本量被夸大,相关可能只反映个体间差异。Bland 与 Altman 1995 年在 BMJ 分别给出了受试者内相关和受试者间相关的计算方法。
线性回归(本页实测)
log(臭氧) ~ 气温 + 风速:气温系数 0.0574(95% CI 0.0446 至 0.0702),即气温每升高 1°F,臭氧浓度约增加 exp(0.0574)−1=5.9%;风速系数 −0.0525(95% CI −0.0865 至 −0.0186);R²=0.582。R 的 lm 与 statsmodels 的 ols 结果一致。对数变换后的系数按百分比变化解释。
Logistic 回归(本页实测)
infert 数据:自然流产次数每增加 1 次,OR=3.37(Wald 95% CI 2.22 至 5.12),P=1.2×10⁻⁸。R 的 confint(glm) 默认是剖面似然区间(2.24 至 5.19),statsmodels 和 SPSS 给出的是 Wald 区间,与 R 的 confint.default 相同。两种区间在大样本时接近,小样本或 OR 很大时差别明显。
Cox 回归(本页实测)
survival::lung(n=228,165 个事件):女性相对男性 HR=0.599(95% CI 0.431 至 0.831),P=0.0022;年龄 HR=1.017(95% CI 0.999 至 1.036),P=0.065。cox.zph 全局检验 P=0.25,比例风险假定未被拒绝。R 的 coxph 与 lifelines 默认用 Efron 法处理同时发生的事件,结果一致;statsmodels 的 PHReg 默认用 Breslow 法,性别系数为 −0.51256(R 为 −0.51322)。
常见错误
以下错误都可以在投稿前自查,每条给出后果和改法。
重复测量或配对数据当独立样本
后果是标准误估计错误。本页 sleep 数据实测:配对 t 检验 P=0.0028,误用独立样本 t 检验 P=0.079。同一患者多个时间点用普通方差分析、同一患者多个病灶当多个样本,都属于这类错误。改法:配对 t、重复测量方差分析或混合模型,分析单位与抽样单位一致。
多组之间做两两 t 检验
后果是假阳性增加。本页 PlantGrowth 实测:ctrl 与 trt2 两两 t 检验 P=0.048,Tukey 校正后 P=0.198。改法:先做方差分析或 Kruskal-Wallis,再用 Tukey、Games-Howell、Dunnett 或 Dunn 检验。
把相关当因果,把相关当一致
观察性数据中的相关可能来自混杂。论文措辞写“相关”“关联”,不写“导致”“影响”;需要调整混杂时用多因素回归,并列出调整的变量。评价测量一致性用 Bland-Altman 法。
样本量小却报告大量检验
每组 10 例做 20 个指标的比较,即使药物完全无效,期望也会有 1 个 P<0.05。改法:在方案中指定主要结局;其余结局按探索性分析报告,或做多重比较校正。
只报 P 值,不报效应量与置信区间
P 值不能反映差异大小。SAMPL 指南要求主要结局给出效应估计(均数差、率差、OR、HR 等)及 95% CI。同样 P=0.04,均数差 0.5 mmHg 和 15 mmHg 的临床意义完全不同。
P≥0.05 写成“两组无差异”
没有统计学意义不等于没有差异(Altman 与 Bland 1995,BMJ)。小样本时置信区间往往同时包含有临床意义的差异和 0。改法:写“差异无统计学意义”,并报告置信区间;要证明两组相当需要等效性或非劣效设计。
用 SE 描述数据变异
SE 是推断统计量,约等于 68% 置信区间的半宽。SAMPL 指南要求用 SD 描述近似正态数据,格式写成“均数(SD)”,不写“均数 ± SD”;偏态数据用中位数和四分位数间距,并给出上下界。
报告规范
按 SAMPL 指南(Lang 与 Altman)整理。目标期刊有自己的统计要求时以期刊为准。
效应量的选择:两组均数用 Hedges g(小样本时比 Cohen d 偏倚小);配对设计常用 dz,即差值均数除以差值 SD。不同软件的“配对 Cohen d”定义不同:本页 sleep 数据中 dz=1.28,pingouin 的 ttest(paired=True) 输出的 cohen_d 是 0.83(用两次测量 SD 的平均值作分母)。论文中写明计算公式。Cohen 的 0.2、0.5、0.8 小中大分界来自行为科学,医学研究优先用原始单位的差值和最小临床重要差异来解释。
| 结果类型 | 报告写法示例(数据来自本页实测) |
|---|---|
| 两组均数比较 | 6 月与 8 月臭氧浓度分别为 29.4(18.2)与 60.0(39.7)ppb,均数差 −30.5 ppb(95% CI −50.7 至 −10.4),Welch t=−3.09,df=30.0,P=0.004,Hedges g=−0.96(95% CI −1.61 至 −0.30)。 |
| 配对比较 | 药物 2 比药物 1 平均多增加睡眠 1.58 小时(95% CI 0.70 至 2.46),配对 t=4.06,df=9,P=0.003。 |
| 多组比较 | 3 组干重差异有统计学意义,F(2, 27)=4.85,P=0.016,ω²=0.20;Tukey 检验显示 trt2 组比 trt1 组高 0.87 g(95% CI 0.17 至 1.56,校正 P=0.012)。 |
| 率的比较 | 有自然流产史者在病例组中的比例高于对照组,OR=4.24(95% CI 2.35 至 7.80),Fisher 精确检验 P<0.001。 |
| 生存分析 | 调整年龄后,女性的死亡风险低于男性,HR=0.60(95% CI 0.43 至 0.83),P=0.002。 |
- P 值写等式:P=0.03、P=0.22,不写 P<0.05 或“NS”。最小只需报告到 P<0.001,遗传关联研究除外。
- 主要结局报告效应估计和 95% CI,例如均数差、率差、OR、HR 及其区间。
- 写明每个分析用的具体方法,不要只在统计方法段落末尾列出所有方法的名称。
- 写明是单侧还是双侧检验(单侧检验要给理由)、检验水准 α、是否以及如何做多重比较校正。
- 写明假设如何核查:偏态数据用了非参数方法,配对数据用了配对方法,线性回归检查了线性关系和残差。
- 百分比给出分子和分母,各分析给出样本量。
- 写明统计软件名称和版本,例如 R 4.4.3(car 3.1)、SPSS 27.0。
- 事后分析和未预先计划的亚组分析标注为探索性。
软件对照
三种软件对同一方法的默认设置不同,同一份数据可能得到不同 P 值。下表的 R 与 Python 结果均为本页实测;SPSS 部分按 IBM 文档核对菜单,未在本机运行。
R aov,气缸数放在前面(I 型) P = 0.056
R aov,变速箱放在前面(I 型) P = 4.9e-07
car::Anova type = 2 / pingouin P = 0.056
car::Anova type = 3(contr.sum) P = 0.083
statsmodels anova_lm(typ=3) P = 0.083 # 与 SPSS 默认 III 型对应| 方法 | R | Python | SPSS 菜单 | 默认值差异 |
|---|---|---|---|---|
| Welch t / Student t | t.test(y ~ g);var.equal = TRUE 为 Student | scipy.stats.ttest_ind(a, b, equal_var=False);pingouin.ttest | 分析 > 比较平均值 > 独立样本 T 检验 | R 默认 Welch;SciPy 默认 Student;pingouin 默认 correction='auto',只在两组样本量不等时用 Welch;SPSS 两行都输出 |
| Mann-Whitney U | wilcox.test(y ~ g) | scipy.stats.mannwhitneyu;pingouin.mwu | 分析 > 非参数检验 > 独立样本 | 有结时 R 与 SciPy 都用正态近似加连续性校正,本页实测 P 相同(0.000121) |
| 配对 t / Wilcoxon 符号秩 | t.test(x, y, paired = TRUE);wilcox.test(x, y, paired = TRUE) | scipy.stats.ttest_rel;scipy.stats.wilcoxon | 分析 > 比较平均值 > 成对样本 T 检验;非参数检验 > 相关样本 | 有零差值和结时,R 用正态近似加校正(P=0.0091),SciPy 1.18 默认给出精确 P(0.0039);设 method='approx', correction=True 后与 R 相同 |
| 单因素方差分析 / Welch 方差分析 | aov;oneway.test | pingouin.anova;pingouin.welch_anova | 分析 > 比较平均值 > 单因素 ANOVA 检验(选项中勾选 Welch) | 结果一致 |
| 事后检验 | TukeyHSD;rstatix::games_howell_test;rstatix::dunn_test | pingouin.pairwise_tukey;pairwise_gameshowell;statsmodels pairwise_tukeyhsd | 单因素 ANOVA 的事后比较:Tukey、Dunnett、Games-Howell | 结果一致 |
| 多因素方差分析 | car::Anova(lm(...), type = 3),需设 contr.sum | statsmodels anova_lm(typ=3),因子用 C(x, Sum);pingouin.anova 默认 II 型 | 分析 > 一般线性模型 > 单变量(默认 III 型) | R 的 aov 和 statsmodels 默认 I 型(顺序)平方和,不平衡设计下结果随变量顺序改变,见下方实测 |
| 重复测量方差分析 | afex::aov_ez | pingouin.rm_anova(correction=True) | 分析 > 一般线性模型 > 重复测量 | 结果一致,都输出 Mauchly 检验和 GG 校正 |
| 卡方 / Fisher | chisq.test;fisher.test | scipy.stats.chi2_contingency;fisher_exact | 分析 > 描述统计 > 交叉表 > 统计:卡方 | R 与 SciPy 对四格表默认 Yates 校正;Fisher 的 OR 定义不同(条件 MLE 对样本 OR) |
| McNemar | mcnemar.test | statsmodels mcnemar | 交叉表 > 统计:McNemar | R 默认连续性校正卡方,statsmodels 默认精确二项检验 |
| 相关 | cor.test(method = 'pearson' / 'spearman') | scipy.stats.pearsonr;pingouin.corr | 分析 > 相关 > 双变量 | 结果一致;pingouin 直接给出 95% CI |
| 线性 / Logistic 回归 | lm;glm(family = binomial) | statsmodels ols;logit | 分析 > 回归 > 线性;二元 Logistic | R 的 confint(glm) 是剖面似然区间,statsmodels 与 SPSS 是 Wald 区间 |
| Cox 回归 | survival::coxph | lifelines.CoxPHFitter;statsmodels PHReg | 分析 > 生存分析 > Cox 回归 | R 与 lifelines 默认 Efron 结处理,statsmodels 默认 Breslow |
| 多重比较校正 | p.adjust(p, 'holm' / 'BH') | statsmodels multipletests(method='holm' / 'fdr_bh') | 部分过程内置 Bonferroni | 结果一致 |
| 主成分分析 | prcomp(x, scale. = TRUE) | sklearn PCA + StandardScaler | 分析 > 降维 > 因子(提取方法选主成分) | R 的 rotation 与 sklearn 的 components_ 是特征向量,SPSS 成分矩阵是载荷;sklearn 的 explained_variance_ 比相关矩阵特征值大 n/(n−1) 倍 |
可运行代码
以下代码在本页的实测环境中运行通过。R 代码直接使用内置数据集;Python 代码读取用 R 导出的 CSV,以保证两边数据完全相同。
R 端如果同时加载 rstatix 与 effectsize,两者都有 cohens_d 函数,后加载的会覆盖前者,参数不兼容时会报 unused argument (pooled_sd = FALSE)。写成 effectsize::cohens_d 可以避免。
pingouin 首次导入较慢(本机首次约 80 秒,用于编译缓存),之后正常。
# R 4.4:install.packages(c("car", "effectsize", "rstatix", "afex", "survival"))
library(car); library(effectsize); library(rstatix); library(afex); library(survival)
# 两独立组:airquality 6 月(n=9)与 8 月(n=26)臭氧浓度
aq <- subset(airquality, Month %in% c(6, 8) & !is.na(Ozone)); aq$Month <- factor(aq$Month)
t.test(Ozone ~ Month, data = aq) # R 默认 Welch
t.test(Ozone ~ Month, data = aq, var.equal = TRUE) # Student t,对应 SPSS 第一行
wilcox.test(Ozone ~ Month, data = aq, conf.int = TRUE)
effectsize::hedges_g(Ozone ~ Month, data = aq, pooled_sd = FALSE)
# 配对:sleep 数据,同一受试者两种药物
w <- reshape(sleep, idvar = "ID", timevar = "group", direction = "wide")
t.test(w$extra.2, w$extra.1, paired = TRUE)
wilcox.test(w$extra.2, w$extra.1, paired = TRUE, exact = FALSE)
# 多组:单因素方差分析、Welch ANOVA、事后检验、Kruskal-Wallis + Dunn
fit <- aov(weight ~ group, data = PlantGrowth); summary(fit)
oneway.test(weight ~ group, data = PlantGrowth) # Welch ANOVA
TukeyHSD(fit)
games_howell_test(PlantGrowth, weight ~ group) # 方差不齐时的事后检验
effectsize::omega_squared(fit)
aq_all <- subset(airquality, !is.na(Ozone)); aq_all$Month <- factor(aq_all$Month)
kruskal.test(Ozone ~ Month, data = aq_all)
dunn_test(aq_all, Ozone ~ Month, p.adjust.method = "holm")
# 重复测量:Indometh,6 名受试者 5 个时间点
ind <- subset(as.data.frame(Indometh), time %in% c(0.5, 1, 2, 4, 8))
ind$Subject <- factor(as.character(ind$Subject)); ind$time <- factor(ind$time)
rm <- aov_ez(id = "Subject", dv = "conc", data = ind, within = "time")
summary(rm) # Mauchly 球形检验与 GG/HF 校正
friedman.test(conc ~ time | Subject, data = ind)
# 分类变量:卡方、Fisher、McNemar
tab <- table(infert$spontaneous > 0, infert$case)
chisq.test(tab)$expected # 先看期望频数
chisq.test(tab, correct = FALSE); fisher.test(tab)
mcnemar.test(matrix(c(794, 86, 150, 570), 2))
# 相关与回归
cor.test(aq_all$Ozone, aq_all$Temp) # Pearson,带 95% CI
cor.test(aq_all$Ozone, aq_all$Temp, method = "spearman", exact = FALSE)
m <- lm(log(Ozone) ~ Temp + Wind, data = aq_all); summary(m); confint(m)
g <- glm(case ~ spontaneous + induced + age, family = binomial, data = infert)
exp(cbind(OR = coef(g), confint.default(g)))
cx <- coxph(Surv(time, status) ~ age + sex, data = lung); summary(cx); cox.zph(cx)
# 多重比较校正
p <- c(0.001, 0.008, 0.012, 0.021, 0.035, 0.048, 0.09, 0.2, 0.41, 0.74)
round(cbind(p, bonf = p.adjust(p, "bonferroni"), holm = p.adjust(p, "holm"), BH = p.adjust(p, "BH")), 4)library(survival)
write.csv(airquality, "airquality.csv", row.names = FALSE); write.csv(sleep, "sleep.csv", row.names = FALSE)
write.csv(PlantGrowth, "PlantGrowth.csv", row.names = FALSE); write.csv(as.data.frame(Indometh), "Indometh.csv", row.names = FALSE)
write.csv(infert, "infert.csv", row.names = FALSE); write.csv(lung, "lung.csv", row.names = FALSE)# Python 3.12:pip install scipy statsmodels pingouin pandas lifelines
# 数据先在 R 中导出:write.csv(airquality, "airquality.csv", row.names = FALSE) 等
import numpy as np, pandas as pd, pingouin as pg
from scipy import stats
import statsmodels.formula.api as smf
from statsmodels.stats.multitest import multipletests
from statsmodels.stats.contingency_tables import mcnemar
aq = pd.read_csv("airquality.csv").dropna(subset=["Ozone"])
x6, x8 = aq.Ozone[aq.Month == 6], aq.Ozone[aq.Month == 8]
print(stats.ttest_ind(x6, x8, equal_var=False)) # scipy 默认 equal_var=True,必须显式写 False 才是 Welch
print(pg.ttest(x6, x8, correction=True)) # pingouin 默认 'auto':只在样本量不等时用 Welch
print(stats.mannwhitneyu(x6, x8))
sleep = pd.read_csv("sleep.csv").pivot(index="ID", columns="group", values="extra")
print(stats.ttest_rel(sleep[2], sleep[1]))
print(stats.wilcoxon(sleep[2], sleep[1], method="approx", correction=True)) # 与 R 默认一致
pg_df = pd.read_csv("PlantGrowth.csv")
print(pg.anova(pg_df, dv="weight", between="group", detailed=True))
print(pg.welch_anova(pg_df, dv="weight", between="group"))
print(pg.pairwise_tukey(pg_df, dv="weight", between="group"))
print(pg.pairwise_gameshowell(pg_df, dv="weight", between="group"))
print(pg.kruskal(aq, dv="Ozone", between="Month"))
ind = pd.read_csv("Indometh.csv"); ind = ind[ind.time.isin([0.5, 1, 2, 4, 8])]
print(pg.rm_anova(ind, dv="conc", within="time", subject="Subject", correction=True))
print(pg.friedman(ind, dv="conc", within="time", subject="Subject"))
inf = pd.read_csv("infert.csv")
tab = pd.crosstab(inf.spontaneous > 0, inf.case).to_numpy()
chi2, p, dof, expected = stats.chi2_contingency(tab, correction=False); print(chi2, p, expected.round(1))
print(stats.fisher_exact(tab))
print(mcnemar(np.array([[794, 150], [86, 570]]), exact=False, correction=True))
print(pg.corr(aq.Ozone, aq.Temp), pg.corr(aq.Ozone, aq.Temp, method="spearman"))
print(smf.ols("np.log(Ozone) ~ Temp + Wind", data=aq).fit().summary())
logit = smf.logit("case ~ spontaneous + induced + age", data=inf).fit(disp=0)
print(np.exp(pd.concat([logit.params, logit.conf_int()], axis=1)))
from lifelines import CoxPHFitter
lung = pd.read_csv("lung.csv")[["time", "status", "age", "sex"]].dropna(); lung["status"] -= 1
print(CoxPHFitter().fit(lung, "time", "status").summary[["exp(coef)", "exp(coef) lower 95%", "exp(coef) upper 95%", "p"]])
p = [0.001, 0.008, 0.012, 0.021, 0.035, 0.048, 0.09, 0.2, 0.41, 0.74]
for m in ["bonferroni", "holm", "fdr_bh"]: print(m, multipletests(p, method=m)[1].round(4))主成分分析
主成分分析(PCA)把多个相关的连续变量合成少数几个互不相关的综合变量,用于降维、构建综合指标或在回归前处理共线性。它描述的是变量的方差结构,不检验假设。
R 的 prcomp 输出 rotation 是特征向量,SPSS“因子分析”菜单中提取方法选主成分时输出的“成分矩阵”是载荷。从 SPSS 成分矩阵得到主成分表达式的系数,需要把每列除以对应特征值的平方根。sklearn 的 explained_variance_ 用 n−1 作除数,而 StandardScaler 用 n 标准化,因此本例中 sklearn 的第一特征值为 2.622,相关矩阵特征值为 2.613;方差解释比例不受影响。
library(survival)
labs <- c("bili", "chol", "albumin", "copper", "alk.phos", "ast", "trig", "platelet", "protime")
pb <- na.omit(pbc[, labs]) # 276 例完整病例
pca <- prcomp(pb, scale. = TRUE) # 必须标准化:各指标单位不同
summary(pca) # 方差解释比例与累计比例
eig <- pca$sdev^2 # 特征值
loadings <- sweep(pca$rotation, 2, pca$sdev, "*") # 载荷 = 特征向量 × sqrt(特征值),即 SPSS 成分矩阵
round(loadings[, 1:2], 3)
# 平行分析:保留特征值大于随机数据 95 分位数的主成分
set.seed(2026)
sim <- replicate(500, eigen(cor(matrix(rnorm(nrow(pb) * ncol(pb)), nrow(pb))))$values)
rbind(observed = round(eig, 3), random95 = round(apply(sim, 1, quantile, 0.95), 3))import numpy as np, pandas as pd
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
pb = pd.read_csv("pbc_labs.csv") # R 中 write.csv(na.omit(pbc[, labs]), ...) 导出
pca = PCA().fit(StandardScaler().fit_transform(pb))
print(pca.explained_variance_ratio_.round(4)) # 与 R summary(pca) 的 Proportion of Variance 相同
eig = np.linalg.eigvalsh(np.corrcoef(pb.T.to_numpy()))[::-1] # 相关矩阵特征值,与 R、SPSS 相同
loadings = pca.components_.T * np.sqrt(eig) # 主成分符号可能与 R 相反,解释时看相对方向
print(pd.DataFrame(loadings[:, :2], index=pb.columns, columns=["PC1", "PC2"]).round(3))- 01
确认适用条件
变量为连续变量,变量间有中等以上相关(相关矩阵中多数 |r|>0.3)。样本量常用经验是至少为变量数的 5 到 10 倍。KMO 和 Bartlett 球形检验来自因子分析,PCA 中可作参考,不是必需步骤。
- 02
标准化后再分析
单位不同的变量必须标准化(R 中 scale. = TRUE,即基于相关矩阵)。本页实测 PBC 数据(survival::pbc 中 9 项实验室指标,276 例完整病例):不标准化时第一主成分解释 98.3% 的方差,几乎全部来自数值最大的碱性磷酸酶,其载荷为 −1.000;标准化后第一主成分解释 29.0%。
- 03
决定保留几个主成分
标准化后特征值依次为 2.613、1.483、0.991、0.876……Kaiser 准则(特征值>1)保留 2 个;平行分析(与同样大小的随机数据特征值 95 分位数 1.362、1.249、1.165 比较)也保留 2 个。第 3 个特征值 0.991 贴近 1,Kaiser 准则在这种边界情况下容易多留或少留,平行分析更稳定。累计方差 85% 是国内教程常用的标准,本例前 2 个主成分累计只有 45.5%,说明这些指标不能被少数几个成分概括。
- 04
读载荷
载荷是变量与主成分的相关系数,等于特征向量乘以对应特征值的平方根。本例第一主成分上胆红素(0.836)、铜(0.661)、AST(0.618)、甘油三酯(0.561)、胆固醇(0.527)载荷较大,白蛋白为 −0.476,可解释为肝损伤严重程度;第二主成分主要由血小板(0.756)、凝血酶原时间(−0.533)和胆固醇(0.513)构成。主成分的正负号是任意的,R 与 Python 的第一主成分符号相反,解释时看变量之间的相对方向。
- 05
报告
报告标准化方法、保留个数及依据、各主成分的特征值和方差解释比例、载荷矩阵(通常列出 |载荷|≥0.4 的变量)。用主成分得分进入回归时,说明得分的计算方法。
国内经验
以下来自“小白学统计”(冯国双)、医学统计教材学习笔记和 CSDN 上的 SPSS 主成分分析教程,已与本页实测和英文文献核对。
“常规药 + 新药”与“常规药”两组比较不能证明新药有效
冯国双在审稿经验中举例:24 只小鼠分为对照、常规药 A、A+新药 B 三组,作者用 A+B 组与 A 组的差异证明 B 有效。A 与 B 可能有交互作用,这个差异不能完全归因于 B。改法是增设单用 B 组,构成 2×2 析因设计,用两因素方差分析同时检验主效应和交互作用。
术后多个时间点不要按随机区组设计分析
同一文章中的第二个例子:46 例 LASIK 患者在术前、术后 1 天、1 个月、3 个月、6 个月测视野,作者按随机区组方差分析处理。时间点不能随机分配,同一患者相邻时间点的相关通常更强,不满足随机区组的假设。应按重复测量设计分析,并报告球形检验和校正,或者用混合模型。
国内教材的四格表与配对卡方规则
医学统计教材笔记中的规则:四格表 n≥40 且所有 T≥5 用 Pearson 卡方,n≥40 且 1≤T<5 用校正卡方,n<40 或 T<1 用 Fisher 精确检验;配对四格表 b+c<40 时用 McNemar 校正公式。国内期刊审稿多按这套规则。R 的 chisq.test 不论条件都默认校正,按教材规则报告时要设 correct = FALSE 并自行判断。
SPSS 成分矩阵除以特征值平方根得到特征向量
CSDN 上的 SPSS 主成分分析教程(如 zyq357 的《主成分分析法的SPSS操作》)普遍做法是:用“降维 > 因子”菜单做 PCA,把成分矩阵每列除以对应特征值的平方根,得到主成分表达式的系数。本页用 R 验证了这一关系:rotation 乘以 sdev 后与载荷矩阵一致。
中文教程中关于事后检验的两处错误说法
部分中文教程写“Tukey 法只能用于各组例数相等的情形”和“SNK 法控制了 I 类错误”。前者不成立,例数不等时使用 Tukey-Kramer 法,R 与 SPSS 自动处理;后者只在全部组均数相等时成立,部分组相等时 SNK 不能控制族错误率。
交给 Agent
数据整理、选检验、R 与 Python 双重计算、按 SAMPL 格式写结果,这些步骤可以交给科学智能体完成,判断和解释仍由研究者负责。
一句话指令示例:“这是我的临床数据 data.xlsx,主要结局是 6 个月时的 HbA1c,比较三个治疗组,还有基线和 3 个月的重复测量。请按数据类型选择检验方法,用 R 和 Python 分别计算并核对,按 SAMPL 指南写出结果段落和表格。”
智能体在隔离云电脑中执行:读取数据并检查缺失、异常值和变量类型;画分组直方图与 Q-Q 图,计算偏度和峰度;按本页决策表选择整体检验和事后检验;在 R 与 Python 中分别计算,逐项比较 P 值、效应量和置信区间,有差异时定位到默认设置;生成结果表、图和方法描述段落。工作区保留脚本、软件版本、日志和中间结果,智能体会对结果做对抗审阅。关闭本机后任务继续运行。
读者仍需核对:分析单位是否与抽样单位一致;主要结局与次要结局的划分是否与方案一致;多重比较校正的检验族范围;结果的临床意义解释。
参考资料
- Lang T, Altman DG. SAMPL Guidelines(EQUATOR Network) — P 值写法、效应量与 95% CI、均数(SD)格式、SE 不用于描述变异
- Delacre M, Lakens D, Leys C. Why psychologists should by default use Welch's t-test instead of Student's t-test. Int Rev Soc Psychol 2017 — Welch t 作为默认方法的依据;先检验方差齐性再选择的问题
- Rochon J, Gondan M, Kieser M. To test or not to test: preliminary assessment of normality. BMC Med Res Methodol 2012 — 先做正态性检验再选 t 检验或秩和检验的两阶段做法
- Lumley T, et al. The importance of the normality assumption in large public health data sets. Annu Rev Public Health 2002 — 大样本下 t 检验与线性回归对非正态的稳健性,“足够大”常在 100 以内
- Kim HY. Assessing normal distribution (2) using skewness and kurtosis. Restor Dent Endod 2013 — 按样本量划分的偏度、峰度判断阈值
- Hart A. Mann-Whitney test is not just a test of medians. BMJ 2001 — Mann-Whitney 检验结果的解释
- Bland JM, Altman DG. Multiple significance tests: the Bonferroni method. BMJ 1995 — 多重检验的假阳性与 Bonferroni 校正
- Bender R, Lange S. Adjusting for multiple testing—when and how? J Clin Epidemiol 2001 — 确证性与探索性研究中是否校正
- NEJM 2019 统计报告指南解读(Harrington 等) — 未预先规定校正方法的次要结局只报告效应估计与 95% CI
- Campbell I. Chi-squared and Fisher–Irwin tests of two-by-two tables with small sample recommendations. Stat Med 2007 — N−1 卡方与 Fisher 检验的选择
- Bland JM, Altman DG. Statistical methods for assessing agreement between two methods of clinical measurement. Lancet 1986 — 相关系数不能评价一致性
- Bland JM, Altman DG. Statistics Notes 系列目录(York 大学) — 重复观测的相关系数计算、Absence of evidence is not evidence of absence 等
- Peduzzi P, et al. A simulation study of the number of events per variable in logistic regression analysis. J Clin Epidemiol 1996 — EPV≥10 的来源
- IBM SPSS Statistics 27 新功能 — SPSS 27 起 t 检验与单因素方差分析可输出效应量及置信区间
- IBM SPSS 教程:Independent-Samples T Test 输出表 — SPSS 独立样本 t 检验两行结果的含义
- SciPy 文档:scipy.stats.ttest_ind — equal_var 默认为 True
- pingouin 文档:pingouin.ttest — correction='auto' 的行为
- 经验帖:医咖会转载“小白学统计”《论文中方差分析的常见误用》(CSDN) — 析因设计缺组与重复测量误用随机区组的审稿案例
- 经验帖:《实用医学统计学与SAS应用》学习笔记:分类变量资料的比较(CSDN) — 国内教材的四格表、配对卡方与 R×C 表规则
- 经验帖:主成分分析法的SPSS操作(CSDN) — SPSS 成分矩阵除以特征值平方根的做法
- 经验帖:方差分析中两两多重比较方法的含义及如何选择(CSDN) — 中文教程中关于 Tukey 与 SNK 的错误说法,本页予以更正