如何在 R 中排列几对变量之间的相关性?

How to permute correlations between several pairs of variables in R?

提问人:Adam9 提问时间:10/30/2023 最后编辑:Adam9 更新时间:11/1/2023 访问量:78

问:

我想计算来自两个数据帧的变量对之间的相关性,最好使用 cor.test,这样我就可以使用估计值或统计量来比较 p 值。我的真实数据(而不是练习虚拟数据)在 df1 中有 20 个样本和 40 个变量,在 df2 中有 20 个样本和 345 个变量。

他们研究两个变量之间的互换相关性的一些示例使用了 for 循环、https://bookdown.org/curleyjp0/psy317l_guides5/permutation-testing.html#correlation-coefficient-permutation-testshttps://dgarcia-eu.github.io/SocialDataScience/5_SocialNetworkPhenomena/056_PermutationTests/PermutationTests,如果只有两个变量/向量,则有效。

我尝试使用 foreach 将我的每个 y 变量在 df2 中置换 1,000 次,然后通过查看置换统计量 >= 原始统计量 / 排列数的次数来计算 p 值。我一直在练习 10 种排列和一个较小的数据集,看看我是否可以让我的代码正常工作

df <- as.data.frame(matrix(round(runif(n=12*12, min=1, max=20), 0), ncol=12))
colnames(df) <- paste0("a", ncol(df))
df2 <- as.data.frame(matrix(round(runif(n=12*20, min=1, max=20), 0), ncol=20))
colnames(df2) <- paste("b", ncol(df2) )
comp <- expand.grid(colnames(df1), colnames(df2))


res <-  foreach(i=1:nrow(comp), .combine=rbind, .packages=c("magrittr", "dplyr")) %dopar% {
perm <- \(){
N <- 10
samp <- sample(nrow(df2))
cor.test(df[, comp[i,1]], df2[samp, comp[i,2]], method="spearman", exact=FALSE)[c("estimate")]
}
perm_stat <- replicate(N, perm())
orig_stat <- cor.test(df[, comp[i,1]], df2[, comp[i,2]], method="spearman", exact=FALSE)[c("estimate")] 
(sum(abs(perm_stat) >= abs(orig_stat)) + 1)/N 
   }

  res2 <- as.data.frame(unlist(res)) %>% dplyr::mutate(Var1=comp[,1], Var2=comp[,2])

如果我对所有条形orig_stat进行散列处理,它会运行以获得 df 和 df2 中变量之间相关性的系数/估计值。但显然没有进行排列。我应该尝试通过 foreach 使用双循环还是寻找替代方法,例如 Map 的并行版本,例如 mcmapply。

   ##double loop format 
   out <- foreach(j=1:ncol(df1), .combine = 'rbind', .packages=c("magrittr", "dplyr")) %:%
      foreach(i = 1:ncol(df2), .combine = 'c') %dopar% {
       a <- cor.test(df1[,j], df2[,i], method = "spearman")$p.value
     }
r 并行处理 排列 相关 parallel.foreach

评论

0赞 Nir Graham 10/30/2023
你的标题是一个与速度有关的问题,但你的正文不是关于这个,而是关于排列正在发生的明显程度?
0赞 Adam9 10/30/2023
@NirGraham,我现在更改了标题 - 它更多地与如何设计正确的代码来排列相关性有关,当我感兴趣的变量位于两个数据帧中时。

答:

0赞 jblood94 10/31/2023 #1

这里似乎对排列测试的使用存在一些混淆。 已经提供了您需要的信息 - 不需要排列。cor.test

例如,假设返回 p 值 0.05。对于使用 Spearman 的 rho 统计量的双侧检验,解释是 和 之间的 Spearman 秩相关系数比 和 之间的系数在大约 5% 的时间内离 0 更远。cor.test(x, y, method = "spearman")xy[sample(length(y))]xy

同样,如果我们重复调用 ,我们会看到 p 值小于 0.05,大约有 5% 的时间。展示:cor.test(x, y[sample(length(y))], method = "spearman")

set.seed(293885308L)
x <- runif(20)
y <- runif(20)
correl <- cor(x, y, method = "spearman")

# a single `cor.test`
(p <- cor.test(x, y, method = "spearman")$p.value)
#> [1] 0.04984582

# a permutation test on top of `cor.test`
mean(replicate(1e5, cor.test(x, y[sample(20)], method = "spearman")$p.value) <= p)
#> [1] 0.04982

# a permutation test instead of `cor.test`
mean(abs(replicate(1e6, cor(x, y[sample(20)], method = "spearman"))) >= correl)
#> [1] 0.04973

对于问题中描述的相对较小的数据集,我们可以快速轻松地获得所有成对列组合的 p 值:

df <- as.data.frame(matrix(runif(20*40), 20, 40))
df2 <- as.data.frame(matrix(runif(20*345), 20, 345))

microbenchmark::microbenchmark(
  cor.test = mapply(\(y) sapply(df, \(x) cor.test(x, y, method = "spearman")$p.value), df2),
  times = 10
)
#> Unit: seconds
#>      expr      min       lq     mean   median       uq      max neval
#>  cor.test 1.739906 1.753571 1.818344 1.773926 1.841813 1.989383    10

评论

0赞 Adam9 11/1/2023
谢谢你。更重要的是,我想使用排列来洗牌我的 x 和 y(或仅 y)或更具体地说排名,因为我正在使用 Spearman,然后比较来自排列的检验统计量大于或等于原始相关性计算的检验统计量的次数,除以排列的数量。不完全确定我是否可以说原假设是相关性是排名相关的,替代方案是它们不依赖于排名,然后可以使用来自转换的 p 值来查看?
0赞 jblood94 11/1/2023
我从你的代码中了解你想做什么。我要说的是,正如我所演示的那样,在表现良好的统计测试(这里)之上添加排列测试是多余的。不用担心排列测试,只需使用!顺便说一句,只是或只是或两者兼而有之,在对排列的相关性进行采样时都是等价的。cor.testcor.testxyxy
0赞 Adam9 11/3/2023
不过,这取决于原始数据集吗?因此,如果来自变量 x 和 y 的每对观测值都有助于所看到的相关性/关系,那么排列就不会产生差异。但是,如果我没有排列的原始相关系数在很大程度上仅受所有 x 和 y 中的一两对的影响,那么随机重采样将有助于确定是否存在真正的相关性,或者我们是否不太可能看到这一点(如果我们没有驱动它的极少数数据点)。也许我需要一种完全不同的方法......
0赞 jblood94 11/3/2023
这正是这样做的。它近似于随机配对观测值的相关系数(在本例中为 Spearman)的绝对值大于或等于观测配对的系数的概率。cor.test
0赞 jblood94 11/3/2023
该方法取决于您的最终目标,而您的问题中未包含该目标。无论您选择哪种方法,最好记住,在 40*345 = 13800 个统计检验中,您可能会得到一些非常低的 p 值,即使 和 是随机和独立生成的,如您的示例所示。dfdf2