选择所有可能的变量组合

Selecting all possible combinations of variables

我有一个数据集,其中我们用 18 个项目和政治倾向来衡量幸福感(我们暂时假设政治倾向是用一个项目衡量的)。

一个人的幸福感得分可以通过取所有 18 个项目的平均值来计算,也可以通过取每个可能的项目组合(例如,一项、两项的所有组合等)的平均值来计算,结果sum(choose(18, 0:18)) = 262,144 种可能的组合。

我感兴趣的是幸福感和政治取向之间的相关系数如何根据幸福感的计算方式而变化。也就是说,我有兴趣获得所有 18 个(选择(18,1)= 18)相关系数,如果幸福感是用 18 个项目中的每一个来评估的,然后与政治取向相关,那么所有 153 个相关系数,如果幸福感是用 2 项的所有可能组合计算,然后与政治倾向等相关。所以最后我会寻找 262,144 个相关系数。

数据集看起来像这样(只有超过 10,000 名参与者),而 v19 是政治取向,v1 到 v18 是幸福项目。

df <- as.data.frame(matrix(rnorm(190), ncol = 19)) 

本质上,我问的是如何计算 2 个项目、3 个、...、17 个幸福项目的所有组合的平均值。我遇到了 tidyrexpand() 函数,但这似乎在做其他事情。

以下是一些步骤:(1) 计算 18 个因素组合的平均值;然后 (2) 将这些组合平均值中的每一个与第 19 列(政治取向)相关联。

set.seed(42)
df <- as.data.frame(matrix(rnorm(190), ncol = 19))
df[,1:3]
#          V1      V2      V3
# 1   1.37096  1.3049 -0.3066
# 2  -0.56470  2.2866 -1.7813
# 3   0.36313 -1.3889 -0.1719
# 4   0.63286 -0.2788  1.2147
# 5   0.40427 -0.1333  1.8952
# 6  -0.10612  0.6360 -0.4305
# 7   1.51152 -0.2843 -0.2573
# 8  -0.09466 -2.6565 -1.7632
# 9   2.01842 -2.4405  0.4601
# 10 -0.06271  1.3201 -0.6400
rowMeans(df[,c(1,2)])
#  [1]  1.3379  0.8610 -0.5129  0.1770  0.1355  0.2649  0.6136 -1.3756 -0.2110  0.6287
rowMeans(df[,c(1,3)])
#  [1]  0.53216 -1.17300  0.09561  0.92377  1.14973 -0.26830  0.62713 -0.92891  1.23926 -0.35135
rowMeans(df[,c(2,3)])
#  [1]  0.4991  0.2527 -0.7804  0.4679  0.8809  0.1027 -0.2708 -2.2098 -0.9902  0.3401

我显示了三种组合的行均值,因为我想验证在下一步中找到这些值的位置。

means <- lapply(1:3, function(N) {
  do.call(cbind,
          lapply(asplit(combn(18, N), 2),
                 function(ind) rowMeans(df[, ind, drop = FALSE])))
})
str(means)
# List of 3
#  $ : num [1:10, 1:18] 1.371 -0.565 0.363 0.633 0.404 ...
#  $ : num [1:10, 1:153] 1.338 0.861 -0.513 0.177 0.135 ...
#  $ : num [1:10, 1:816] 0.7897 -0.0198 -0.3992 0.5229 0.722 ...

最后一步生成一个 means 对象,其中包含“1”(单列)、“2”(成对行平均值)和“3”-深度组合平均值。请注意,choose(18,2) 是 153(means[[2]] 中的列数),choose(18,3) 是 816(means[[3]])。每列代表各个列组合的平均值。

我在此处包含 1 (choose(18,1)) 只是为了将所有数据保持在同一结构中,因为我们确实想测试单列的相关性;可以通过其他方法来实现这一点,我倾向于一致性和简单性。

为了验证我们的想法,我将从 means[[2]] 中提取三列,它们对应于我在上面显示的基于直接访问 df 的三个 rowMeans 计算(检查将显示它们是匹配的):

means[[2]][,c(1,2,18)]
#          [,1]     [,2]    [,3]
#  [1,]  1.3379  0.53216  0.4991
#  [2,]  0.8610 -1.17300  0.2527
#  [3,] -0.5129  0.09561 -0.7804
#  [4,]  0.1770  0.92377  0.4679
#  [5,]  0.1355  1.14973  0.8809
#  [6,]  0.2649 -0.26830  0.1027
#  [7,]  0.6136  0.62713 -0.2708
#  [8,] -1.3756 -0.92891 -2.2098
#  [9,] -0.2110  1.23926 -0.9902
# [10,]  0.6287 -0.35135  0.3401

这意味着列的顺序为 1,21,31,4、...、1,18,然后是 2,3(第 18 列),2,4,等等,通过 17,18(第 153 列)。

从这里开始,将这些列中的每一列与 V19 相关联并不困难:

cors <- lapply(means, function(mn) apply(mn, 2, cor, df$V19))
str(cors)
# List of 3
#  $ : num [1:18] 0.2819 -0.3977 0.0426 0.2501 -0.063 ...
#  $ : num [1:153] -0.27 0.168 0.472 0.192 0.6 ...
#  $ : num [1:816] -0.1831 -0.063 -0.3355 0.0358 -0.3829 ...
cor(df$V1, df$V19)
# [1] 0.2819
cor(rowMeans(df[,c(1,2)]), df$V19)
# [1] -0.2702
cor(rowMeans(df[,c(1,3)]), df$V19)
# [1] 0.1677
cor(rowMeans(df[,c(1,2,3)]), df$V19)
# [1] -0.1831
cor(rowMeans(df[,c(1,2,4)]), df$V19)
# [1] -0.06303

由于这样做的方式,应该直接将 3 的 N 更改为您可能需要的任何内容......意识到 choose(18,9) 是 48620,生成这些组合-平均值不是瞬时的,但仍然很容易管理:

system.time({
  means18 <- lapply(1:18, function(N) {
    do.call(cbind,
            lapply(asplit(combn(18, N), 2),
                   function(ind) rowMeans(df[, ind, drop = FALSE])))
  })
})
#    user  system elapsed 
#   41.65    0.58   50.35 
str(means18)
# List of 18
#  $ : num [1:10, 1:18] 1.371 -0.565 0.363 0.633 0.404 ...
#  $ : num [1:10, 1:153] 1.338 0.861 -0.513 0.177 0.135 ...
#  $ : num [1:10, 1:816] 0.7897 -0.0198 -0.3992 0.5229 0.722 ...
#  $ : num [1:10, 1:3060] 0.7062 0.1614 -0.0406 0.24 0.6678 ...
#  $ : num [1:10, 1:8568] 0.6061 0.0569 0.1191 0.0466 0.2606 ...
#  $ : num [1:10, 1:18564] 0.5588 -0.0832 0.3619 0.146 0.2321 ...
#  $ : num [1:10, 1:31824] 0.4265 -0.0449 0.3933 0.3251 0.095 ...
#  $ : num [1:10, 1:43758] 0.2428 -0.0505 0.4221 0.1653 0.0153 ...
#  $ : num [1:10, 1:48620] 0.3839 -0.0163 0.385 0.1335 -0.1191 ...
#  $ : num [1:10, 1:43758] 0.4847 -0.0623 0.4115 0.2592 -0.2183 ...
#  $ : num [1:10, 1:31824] 0.5498 0.0384 0.2829 0.4037 -0.259 ...
#  $ : num [1:10, 1:18564] 0.5019 0.0442 0.2189 0.3281 -0.3759 ...
#  $ : num [1:10, 1:8568] 0.3484 -0.0723 0.2117 0.2262 -0.3471 ...
#  $ : num [1:10, 1:3060] 0.364 -0.102 0.197 0.29 -0.219 ...
#  $ : num [1:10, 1:816] 0.334 -0.155 0.154 0.269 -0.232 ...
#  $ : num [1:10, 1:153] 0.311 -0.242 0.217 0.235 -0.247 ...
#  $ : num [1:10, 1:18] 0.282 -0.291 0.214 0.2 -0.198 ...
#  $ : num [1:10, 1] 0.254 -0.228 0.105 0.283 -0.139 ...

其余过程可以类似的方式完成。