滑动Spearman相关性分析中p值与估计值不一致问题排查
我来帮你拆解这个反直觉的问题——相同的Spearman相关系数估计值却对应不同p值,核心原因其实和秩结(ties)的校正有关,咱们一步步捋清楚:
1. 为什么相同rho会有不同p值?
你提到经典t分布近似中n和r相同则p值一致,但pspearman::spearman.test的t-distribution近似并不是完全照搬经典公式!这个函数专门针对小样本或多结场景做了优化,在计算t统计量时会根据x和y向量中的秩结数量进行校正。
简单来说:即使两个窗口的rho和样本量n相同,只要窗口内数据的结数(即重复值的数量)不一样,pspearman计算出的t统计量和对应的p值就会不同。
2. 验证这个猜想
你可以在相关性函数中加入结数统计,直接观察差异:
psSpearman <- function(x, y) { # 统计x和y中的结数量(重复值组的个数) ties_x <- sum(table(x) > 1) ties_y <- sum(table(y) > 1) out <- pspearman::spearman.test(x, y, alternative = "two.sided", approximation = "t-distribution") %>% broom::tidy() return(data.frame( estimate = out$estimate, statistic = out$statistic, p.value = out$p.value, ties_x = ties_x, ties_y = ties_y )) }
重新运行滑动计算后,筛选出rho相同的行:
Results %>% group_by(estimate) %>% filter(n() > 1) %>% select(estimate, p.value, ties_x, ties_y)
你会发现,这些行的ties_x或ties_y必然存在差异,这就是p值不同的根源。
3. 关于ggplot的视觉误差
先排除数据本身的问题:如果上面的筛选结果显示p值数值确实不同,那和ggplot的颜色插值无关。如果数值相同但颜色显示有差异,你可以尝试将p值转为离散型变量(比如分箱),或者调整颜色标尺的精度来验证。
4. 两种解决方案
方案一:保留结校正(pspearman的优势)
如果你的数据确实存在较多秩结,推荐继续使用pspearman的结果——不同p值其实是更准确的统计结果,反映了不同窗口数据分布的差异。
方案二:使用经典无校正的t分布近似
如果你需要严格保证相同rho和n对应相同p值,可以自己实现经典的Spearman t检验公式:
classicSpearman <- function(x, y) { r <- cor(x, y, method = "spearman") n <- length(x) # 经典t统计量公式 t_stat <- r * sqrt((n - 2)/(1 - r^2)) # 双侧p值 p_val <- 2 * pt(abs(t_stat), df = n - 2, lower.tail = FALSE) return(data.frame( estimate = r, statistic = t_stat, p.value = p_val )) }
替换psSpearman为这个函数后,相同rho和n的窗口p值就会完全一致,但注意:这种方法在多结场景下p值的准确性会下降。
5. 额外验证:确保窗口样本量一致
虽然你设置了allow.fewer = FALSE,但还是可以在函数中加入样本量统计,确认所有窗口的n都是20:
psSpearman <- function(x, y) { n <- length(x) ties_x <- sum(table(x) > 1) ties_y <- sum(table(y) > 1) out <- pspearman::spearman.test(x, y, alternative = "two.sided", approximation = "t-distribution") %>% broom::tidy() return(data.frame( estimate = out$estimate, statistic = out$statistic, p.value = out$p.value, n = n, ties_x = ties_x, ties_y = ties_y )) }
内容的提问来源于stack exchange,提问作者DJV

