所有组合按组取一个

All combinations picking one by group

给定一个组指标变量和组内的一些值:

group = rep(c(1,2), each = 3)
val   = letters[1:6]

cbind(group, val)

     group val
[1,] "1"   "a"
[2,] "1"   "b"
[3,] "1"   "c"
[4,] "2"   "d"
[5,] "2"   "e"
[6,] "2"   "f"

我正在寻找一个矩阵,它给我所有独特的组合,这些组合是将每个组中的 one 元素与每个组中的 one 元素组合而成的其他组。也就是说,每组只允许一个个元素在每个组合中是''active''。

所需的输出是一个矩阵,其中每一列代表一种可能的组合。结果矩阵的前四列可能如下所示:

     [,1] [,2] [,3] [,4]
[1,]    1    0    0    1
[2,]    0    1    0    0
[3,]    0    0    1    0
[4,]    1    1    1    0
[5,]    0    0    0    1
[6,]    0    0    0    0

其中行对应于上面输入矩阵中给出的行。第一列告诉您 a 在组 1 中活跃,d 在组 2 中活跃。第二列告诉您 b 在组 1 中活跃,d 在组 2 中活跃。第三列告诉您 c1 中有效,d2 中有效,依此类推。因此,每列的总和将始终等于组数,因为每个组只允许一个元素处于活动状态。

我对如何以有组织的方式获得所需的输出矩阵感到有点困惑。我一直在考虑枚举所有可能的组合并限制为可行的组合(其中组内生成的向量元素的总和对于所有组来说恰好等于一个),但这可能会导致大数据集的内存问题,我不确定有没有更优雅高效的方法

编辑:解决方案应推广到任意数量的组和组内任意数量的元素 (>1)。

我认为这应该根据需要扩展:

group = rep(c(1,2), each = 3)
val   = letters[1:6]
input = data.frame(group, val)

combos = do.call(expand.grid, split(input$val, input$group))

combo_matrix = matrix(0, nrow = nrow(input), ncol = nrow(combos))
for(i in 1:ncol(combos)) {
  combo_matrix[cbind(match(combos[[i]], input$val), 1:ncol(combo_matrix))] = 1
}

combo_matrix
#      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
# [1,]    1    0    0    1    0    0    1    0    0
# [2,]    0    1    0    0    1    0    0    1    0
# [3,]    0    0    1    0    0    1    0    0    1
# [4,]    1    1    1    0    0    0    0    0    0
# [5,]    0    0    0    1    1    1    0    0    0
# [6,]    0    0    0    0    0    0    1    1    1

它假设 val 值在 input 数据框中不重复。