ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

R语言非参数双因素检验:Scheirer-Ray-Hare方法全解析

R语言非参数双因素检验:Scheirer-Ray-Hare方法全解析 如果你经常和实验数据打交道一定遇到过这种尴尬数据分布明显偏态方差参差不齐偏偏还是双因素试验设计。硬着头皮做双因素方差分析two-way ANOVA心里明白正态性和方差齐性的前提已经破掉了把数据拆成两组分别跑Kruskal-Wallis检验又等于白白丢掉了一个因素的解释力。这时候R语言中的Scheirer–Ray–Hare检验就是一个值得认真考虑的选项。它本质上是把非参数思路扩展到双因素场景先把响应变量全样本排序取秩再对秩做双因素方差分析从而在非正态、异方差的数据上同时判断两个因素及其交互作用是否显著。这个方法在生态学α多样性数据、环境监测、农业田间试验这类经常拿不到正态数据的方向里应用得比很多人想象的更广但R的基础包里没有现成函数网上教程又经常只给一句“用rcompanion包”很多细节要自己踩坑才能摸清。这篇文章就从适用条件、统计原理、R语言实操、结果解读到事后比较把全流程完整过一遍。1. 适用场景判断什么时候必须用这个检验1.1 双因素方差分析的三个前提为什么容易破裂经典双因素方差分析有三个硬前提各组残差近似正态分布、各组总体方差齐性、观测之间相互独立。独立性问题通常在实验设计阶段解决随机化做得好的话问题不大。但正态性和方差齐性这两个条件放在真实数据里非常容易翻车。举几个我实际见过的例子生态学里的Shannon多样性指数经常因为优势种和稀有种数量差异巨大而呈现明显右偏土壤重金属浓度数据叠加了采样误差后往往带长尾行为学中的反应时间、计数类变量几乎很难满足方差齐性就连常见的评分数据、等级数据本质上是离散的硬套连续数据的方差分析并不合适。当这些前提被违背时ANOVA并没有马上失效但代价很明确I型错误率不再稳定显著结果可能只是假象检验功效下降真实差异可能被埋没尤其在各组样本量不均衡时哪怕一个离群点也能把整个结论带偏。用生活化的比喻来说你手里明明不是一块标准的、厚度均匀的面团却硬要用模具压出形状规整的饼干压出来的东西自然不靠谱。此时换用基于秩的非参数检验是最稳妥的思路之一。1.2 Scheirer-Ray-Hare检验是双因素版的Kruskal-WallisKruskal-Wallis检验解决的是“单因素多个水平不满足正态时怎么比较”而Scheirer-Ray-Hare检验简称SRH检验把它推广到了两个因素的情形。这个方法由Scheirer、Ray和Hare在1976年提出核心思想极其朴素既然原始数据不满足正态性那我干脆不管原始值先把所有观测值按大小换成秩然后用双因素方差分析的框架去分析这些秩。这样做的好处很明显秩只保留数据的相对次序自动忽略原始分布的具体形状极端值和偏态的影响被大幅削弱同时双因素方差分析能同时把两个因素和交互作用的变异来源拆开不会像拆成若干个单因素检验那样浪费信息。因此凡是“完全随机化的双因素设计 数据非正态/异方差/有离群点”的场景SRH检验都可以作为双因素ANOVA的替代方案。需要注意的是SRH检验并非唯一选择但它是很多教材和论文中默认会提到的经典方法尤其在生态环境领域出镜率很高。实践里我经常把它当成“双因素非参数检验的第一站”简单、容易解释、现有工具支持也成熟。1.3 分清它和Friedman检验、Aligned Rank Transform的区别很多初学者容易把SRH检验和Friedman检验搞混因为两者都处理“两个因素”的问题。它们其实针对的是完全不同的实验设计检验方法设计类型是否估计交互作用适用于什么场景Scheirer-Ray-Hare完全随机化、各处理组合独立重复可以输出但建议谨慎解读双因素设计每个组合有若干个独立观测Friedman随机区组、重复测量通常不估计每个区组内接受不同处理观测不独立Aligned Rank Transform (ART)完全随机化对交互作用检验更稳健交互作用是需要重点关注的核心结论时换句话说如果你的实验是“处理 × 区组”每个区组里每个处理只有一个值这种情况要用Friedman如果你的实验是“处理A × 处理B”每个组合下都有若干独立重复的样本SRH检验才是对路的。至于ART是更现代的秩变换方法它先把主效应和交互效应分别对齐后再取秩对交互项的检验表现比SRH更好。后面第4章我会再展开什么时候该从SRH换到ART。2. 从原理到R函数先懂逻辑再写代码2.1 检验统计量是怎么算出来的很多教程一上来就让你调包但我觉得哪怕你用rcompanion一键出结果也值得先弄明白数字是怎么来的。SRH检验的完整计算过程分四步。第一步把响应变量所有观测值按从小到大排序赋予秩。如果存在并列值用平均秩处理。这一步就是rank()函数做的事情。第二步对这些秩做双因素方差分析等价于拟合一个线性模型rank_value ~ factorA * factorB方差分析会把秩的总平方和拆解成四个部分[ SS_{total} SS_A SS_B SS_{AB} SS_{residual} ]第三步对每个效应比如因素A计算统计量[ H_A \frac{SS_A}{SS_{total} / (N - 1)} ]注意这里的分母是“秩总平方和除以(N-1)”也就是秩的总均方而不是回归残差的均方。这一点乍看反直觉但它和Kruskal-Wallis检验一脉相承Kruskal-Wallis的H统计量本质上也是“组间秩平方和”除以“总秩均方”。因为秩的总变异在样本量N确定时是固定的用总均方做分母才能让统计量落到卡方分布上。第四步查卡方分布得到p值p_A - pchisq(H_A, df df_A, lower.tail FALSE)自由度就是对应效应在方差分析表中的自由度。整个流程其实就是“取秩 ANOVA 每个效应算一个Kruskal-Wallis式统计量”。所以你可以把SRH检验理解为用双因素方差分析的分解逻辑把Kruskal-Wallis检验扩展到了两个因素。2.2 为什么不能简单解读交互作用这里必须说一个容易被忽略的点SRH检验对主效应的检验效果相对比较成熟但对交互作用的检验近似程度并不算好。不少统计文献在讨论秩变换方法时都指出交互项的统计量分布性质更复杂直接用卡方近似可能产生偏差。这就导致一个实际操作上的原则如果交互作用不显著正常解释两个主效应如果交互作用显著不要轻易下“交互作用导致某某结果”的结论更不要继续解释主效应否则可能把数据结构理解偏了。更稳妥的做法是分组比较、画交互图可视化或者直接改用对交互更友好的ART方法。我在实际使用中也养成了一个习惯先把SRH检验当作探索性分析的起点如果交互项p值在0.05附近波动我会用置换检验或ART再验证一次确保不是近似误差在捣乱。2.3 R语言中的现成函数与手动实现R中提供SRH检验的最常用包是rcompanion函数名就是scheirerRayHare()。常规的公式接口写法如下library(rcompanion) srh - scheirerRayHare(value ~ factorA * factorB, data dat) srh不同版本的包在参数命名上略有差异如果提示参数不匹配用?scheirerRayHare查看当前版本文档即可。不过更推荐你掌握手动实现好处有两个一是加深对原理的理解二是某些环境下不方便装包时抄代码就能跑。核心代码其实很短dat$value_rank - rank(dat$value) fit_rank - lm(value_rank ~ factorA * factorB, data dat) aov_rank - anova(fit_rank) N - nrow(dat) sst - sum((dat$value_rank - mean(dat$value_rank))^2) ms_total - sst / (N - 1) srh_table - data.frame( Df aov_rank$Df, SumSq aov_rank$Sum Sq, H aov_rank$Sum Sq / ms_total, p pchisq(aov_rank$Sum Sq / ms_total, df aov_rank$Df, lower.tail FALSE) ) srh_table - head(srh_table, -1) print(srh_table)最后一行head(..., -1)是把ANOVA表中的残差行去掉。这样得到的三行结果因素A、因素B、交互项和rcompanion输出在本质上是一样的。3. 全流程实操数据模拟到结果解读3.1 构造一个非正态的双因素数据集为了让流程具体化我模拟一个生态学场景“生境类型”和“处理强度”对α多样性指数的影响。用对数正态分布生成偏态数据让它天然不满足ANOVA前提。set.seed(2024) dat - expand.grid( treatment c(Control, Low, High), habitat c(Forest, Grassland), rep 1:12 ) mu - ifelse(dat$treatment High, 10, ifelse(dat$treatment Low, 5, 2)) mu - mu * (dat$habitat Forest dat$treatment ! Control ? 1.5 : 1) dat$value - rlnorm(nrow(dat), meanlog log(mu), sdlog 0.8)注意上面用了一个三元表达式如果你用的是比较老的R版本写成ifelse()嵌套更保险mu - mu * ifelse(dat$habitat Forest dat$treatment ! Control, 1.5, 1)这样生成的数据右偏明显且不同组的方差基本随均值增大而增大正是典型的不满足参数检验条件的数据。3.2 第一步检查数据正态性与方差齐性做任何非参数检验前最好先确认参数检验确实不合适这既是统计规范也是将来写论文时审稿人可能会问的问题。先画个直方图和QQ图par(mfrow c(1, 2)) hist(dat$value, breaks 20, main Histogram, col gray) qqnorm(dat$value); qqline(dat$value, col red)再对残差做Shapiro-Wilk检验m1 - lm(value ~ treatment * habitat, data dat) shapiro.test(residuals(m1))同时用car包做Levene方差齐性检验library(car) leveneTest(value ~ treatment * habitat, data dat)模拟数据的Shapiro检验p值通常很小Levene检验大概率也会出现显著说明“数据非正态 方差不齐”的双重暴击齐了。这时候SRH检验就有充分的用武之地。顺带说一句很多教程只检验原始数据的正态性并不完全严谨。回归模型的假设主要针对残差所以优先看残差的正态性和方差齐性而不是只看原始数据分布。不过对于秩检验来说原始数据分布明显偏态也足以支持放弃参数ANOVA。3.3 第二步正式执行Scheirer-Ray-Hare检验用rcompanion包一行代码得到结果library(rcompanion) srh - scheirerRayHare(value ~ treatment * habitat, data dat) print(srh)输出会是一个包含四列的小表大致长这样Df Sum Sq H p.value treatment 2 ... ... ... habitat 1 ... ... ... treatment:habitat 2 ... ... ...如果不想依赖rcompanion包也可以用我前面写的手动代码直接复现。两个结果的统计量在平衡设计下是一致的。这里我建议你至少手动实现一次然后在同一份数据上对比一下输出能帮你确认自己真的理解了检验内部发生了什么。3.4 第三步解读输出结果输出中最关键的三列是Df、H和p.value。Df是对应因素的自由度。假如treatment有3个水平自由度就是2。H是秩平方和除以总秩均方得到的卡方近似统计量数值越大代表该因素导致的秩差异越明显。p.value是把H放到对应自由度的卡方分布中算出的显著性。有一点要注意表里的Sum Sq是秩的平方和不是原始数据的平方和。它的大小和原始数值尺度没有直接可比性所以写论文时不要把这个数字当成“变异有多大”只适合内部计算。得到结果后先看交互项。如果交互不显著比如p 0.05就可以比较独立地解释两个主效应如果交互显著老老实实按第4章的口径来别偷懒直接照搬主效应结论。3.5 第四步事后比较SRH检验只告诉你“这个因素整体上有没有显著影响”不会告诉你“哪些水平之间有差异”。所以当因素显著且水平数大于2时还需要做多重比较。一个简单直接的做法是用pairwise.wilcox.testpairwise.wilcox.test(dat$value, dat$treatment, p.adjust.method fdr)它会对所有水平两两做Wilcoxon秩和检验然后用FDR方法校正p值。如果你更习惯生态学里常用的Dunn检验可以这样写library(FSA) dunnTest(value ~ treatment, data dat, method bh)对于两个水平的因素比如这里的habitatSRH显著后直接用Mann-Whitney U检验即可wilcox.test(value ~ habitat, data dat)这里有一个小细节如果交互项不显著事后比较可以全样本合并做如果交互项显著更好的做法是固定一个因素的水平在另一个因素各水平内分别做比较比如分别看“Forest里的treatment差异”和“Grassland里的treatment差异”避免平均效应掩盖局部结构。4. 常见问题与避坑指南4.1 因子编码顺序带来的陷阱R的anova()默认使用类型I平方和也就是顺序平方和变量进入模型的先后顺序会影响结果。这在平衡设计下没有影响因为各因素正交顺序无所谓但一旦数据不平衡同样的数据如果交换因子顺序输出就可能变。所以如果你发现自己手动实现的结果和rcompanion输出对不上先检查数据平衡性和因子顺序。解决方式有几种尽量使用平衡设计这是统计上最省心的方案或者改用car::Anova(fit_rank, type 3)计算第三类平方和或者在论文中明确说明使用的是哪种平方和。rcompanion包内部处理相对固定但在非平衡设计下同样存在近似偏差。我的建议很简单能用平衡设计尽量用SRH检验更适合作为快速判断工具复杂不平衡数据最好换成GLM或置换检验。4.2 样本量极小或重复测量时容易误用SRH检验的p值基于卡方近似当各组样本量太小时这种近似会变得不可靠。经验上我建议每个处理组合至少保证5到8个独立重复少于这个数字时结果只能当探索性参考。如果你需要交付审稿人看的结论最好用排列检验验证p值。还有一个容易混淆的点如果实验是随机区组设计每个区组内每个处理只有一个观测值或者同一批样本在不同时间被重复测量这种情况下数据并不独立SRH检验就不适用。此时应改用Friedman检验或混合效应模型而不是强行套SRH。4.3 交互项显著时的正确处理第2章已经提过SRH交互项的结果要谨慎。如果你的分析重点恰好就是交互作用且数据量允许我更推荐使用ARTool包做Aligned Rank Transform分析library(ARTool) art_model - art(value ~ treatment * habitat, data dat) anova(art_model)ART的实现思路是先对每个效应分别“对齐”数据再取秩、再建模对交互项的检验要比SRH稳得多。如果SRH显示交互项显著我的行动路径是这样的先画交互效应图看交互方向固定一个因素分别检验另一个因素在各水平内的简单效应再用ART或者置换检验确认交互显著性写结论时明确区分“探索性结果”和“稳健显著性”。4.4 缺失值、并列值、零值的细节SRH检验用rank()取秩默认遇到缺失值NA会返回NA。所以在做检验之前一定要先清理数据dat - na.omit(dat)因子变量也要确保是factor类型如果直接用数字编码的向量模型会把它当成连续变量处理结果完全跑偏dat$treatment - as.factor(dat$treatment) dat$habitat - as.factor(dat$habitat)并列值方面rank()默认用平均秩所以在有并列数据时会自动处理。这通常不是大问题但如果你的数据里有大量0值或者严重离散性比如超过30%的观测都等于同一个值SRH检验的近似质量也会下降。这种时候我更建议考虑零膨胀模型、负二项GLM而不是硬用秩检验。4.5 为什么α多样性数据经常被推荐用这个检验热搜词里出现“α多样性R语言”不是偶然。Shannon指数、Simpson指数、Chao1指数这些α多样性指标天生就是非负且有上界的实测数据往往强烈右偏很难满足ANOVA的正态性假设。再加上不同处理组的物种均匀度差异很大方差不齐几乎是常态。因此很多宏基因组、微生物生态的教程里处理“两个分类变量对α多样性影响”的问题时会直接推荐SRH检验。它的优势在于不需要对数据进行复杂的转换也能给出可解释的整体显著性而且生态学审稿人普遍认可。但注意如果你手上是微生物组数据用SRH之前最好先想清楚样本是否独立比如同一受试者的多部位样本就不独立以及是否需要控制协变量后者SRH帮不了你应该走PERMANOVA或线性混合模型。5. 结果可视化和发表级展示5.1 用ggplot2画分面箱线图分析做完之后一张清楚的图往往比一整段文字更有说服力。对于双因素设计我喜欢用分面箱线图把两个因素同时展示出来library(ggplot2) p - ggplot(dat, aes(x treatment, y value, fill habitat)) geom_boxplot(alpha 0.7) geom_jitter(width 0.15, alpha 0.3) facet_wrap(~ habitat) theme_bw() labs(x Treatment, y Alpha diversity index, title Effects of treatment and habitat on diversity) print(p)这个图里facet_wrap(~habitat)把生境类型分成两个面板同一面板内再比较不同处理强度信息层次很清楚。如果你担心箱线图掩盖了样本量叠加半透明散点就是很实用的技巧。加显著性标注时可以先用事后比较的结果确定哪些组有显著差异再手动在图上添加星号或字母标记。ggplot里常用annotate()或者geom_text()注意标注位置的横纵坐标要基于实际数据范围微调。5.2 论文报告怎么写发表级论文或报告中关于SRH检验的标准写法大概是Since the data violated the normality and homogeneity of variance assumptions, we used a Scheirer-Ray-Hare test to evaluate the effects of treatment and habitat. The effect of treatment was significant (H 12.34, df 2, p 0.01), while habitat was not statistically significant (H 1.02, df 1, p 0.31). The interaction was not significant (H 0.98, df 2, p 0.61).注意几个要点一定要先交代为什么不用参数ANOVA也就是正态性和方差齐性检验的结果汇报时给出H、自由度和p值不必把SumSq列进文章如果审稿人要求效应量可以用秩数据的epsilon squaredrcompanion包中有对应函数但要明确说明这是基于秩的效应量如果有显著交互且用了ART务必单独说明SRH无法胜任交互检验的理由。图表结合时把p值显著性标记放在箱线图上正文中辅以一两句话不要在同一篇文章里把同样信息重复写三遍。6. 我的体会和扩展建议就我自己的使用体验来说SRH检验是一个“够用但不完美”的方法。它最大的价值在于能在非正态、异方差的双因素设计里快速给你一个整体判断而且实现成本极低适合作为探索性分析的第一道工序。但它毕竟是一个基于秩的近似方法尤其在交互作用、不平衡设计、小样本这些组合条件下结果的稳健性需要额外验证。我现在处理这类数据时通常按这个优先级来如果是快速探索直接上SRH检验看主效应如果数据量足够且交互作用是核心优先用ARTool如果对分布还有建模空间比如计数类响应变量我会倾向用负二项GLM这类更正式的方法而不是只停留在秩检验层面。数据分析很少存在“唯一正确方法”多一个方案交叉验证结论就牢固一分。最后再说一个小技巧SRH检验做完后如果你不确定卡方近似的p值是否可靠可以做一个简单的置换检验交叉验证——把响应变量随机打乱几千次重新计算每个效应的H统计量看看原始H值落在置换分布中的位置。这个思路实现起来不难但能显著增强你对结果的信心。希望这篇全流程解析能帮你少踩几个坑顺利跑通自己的数据。
返回列表