存在重复项时生成唯一组合

时间:2015-09-04 17:28:20

标签: r combinations

我的目标是当我们知道可能存在类似的变量组合时生成唯一的组合列表,因为正在操作的集合的一部分具有重复值。因此,我试图解决的问题是获得所有组合而不替换非不同的项目。 解决方案需要是通用的(即适用于任何N个元素的集合,其中M值为不同的项目。因此,解决方案应该使用N = 4,M = 2(Var1 = Var2,Var3 = Var4)或(Var1 = Var2 = Var3,Var4)等。)。作为我想要做的一个简单例子,取三个变量:X,Y,Z

经典组合是:

X    Y    Z
Y    Z
X    Z
Z
X    Y 
Y  
X

如果我们让X = Y,那么我们有:

X    X    Z
X    Z
X    Z
Z
X    X
X
X

因此,我们有两个不是“唯一”的组合:(X)和(X Z)。

所以,我想要的列表是:

X    X    Z
X    Z
Z
X    X
X

编辑:根据@Sam Thomas推荐的N = 4添加案例

如果我们将其扩展为N = 4,我们有:W,X,Y,Z

W    X    Y    Z
X    Y    Z
W    Y    Z
Y    Z
W    X    Z
X    Z
W    Z
Z
W    X    Y
X    Y
W    Y
Y
W    X
X
W

在这里,我们可以得到M = 2个不同元素的形式:(W = X,Y = Z),(X = Z,W = Y),(X = Y,W = Z),(W = X = Y,Z),(W = Z = Y,X),(W = Z = X,Y),或(X = Y = Z,W)。

在(W = X,Y = Z)的情况下,我们有:

W    W    Y    Y
W    Y    Y
W    Y    Y
Y    Y
W    W    Y
W    Y
W    Y
Y
W    W    Y
W    Y
W    Y
Y
W    W
W
W

输出应为:

W    W    Y    Y
W    Y    Y
Y    Y
W    W    Y
W    Y
Y
W    W
W

在(W = X = Y,Z)的情况下,矩阵最初看起来像:

W    W    W    Z
W    W    Z
W    W    Z
W    Z
W    W    Z
W    Z
W    Z
Z
W    W    W
W    W
W    W
W
W    W
W
W

所需的输出是:

W    W    W    Z
W    W    Z
W    Z
Z
W    W    W
W    W
W

结束修改

使用R,我已经有办法生成二进制矩阵形式的所有可能组合的列表:

comb.mat = function(n){
     c = rep(list(1:0), n)
     expand.grid(c)
}

comb.mat(3)

这给出了:

  Var1 Var2 Var3
1    1    1    1
2    0    1    1
3    1    0    1
4    0    0    1
5    1    1    0
6    0    1    0
7    1    0    0
8    0    0    0

如果我们考虑Var1 = Var2,这个结构会有冗余。例如(2,3)和(6,7)代表同一个对象。因此,免冗余版本将是:

  Var1 Var2 Var3
1    1    1    1
2    0    1    1
4    0    0    1
5    1    1    0
6    0    1    0
8    0    0    0

要添加类似于初始结构的“变量”值,我使用:

nvars = ncol(m)

for(i in 1:nvars){
  m[m[,i]==1,i] = LETTERS[22+i]
}

要修改它以便Var1 = Var2,我只需使用:

  m[m[,i]=="Y",i] = "X"

关于如何从初始矩阵移动到后面的矩阵的任何建议?

特别是如果我们有更多的配对变量?

E.g。 comb.mat(4),with :( Var1 = Var2,Var3 = Var4)或(Var1 = Var2 = Var3,Var4)

1 个答案:

答案 0 :(得分:2)

我相信这包含所有组合。

m <- comb.mat(3)

res <- lapply(split(m, m$Var3), function(x, vars=c("Var1", "Var2")) {
   x[Reduce(`==`, x[vars]) | cumsum(Reduce(xor, x[vars])) == 1, ]
})

do.call(rbind, res)
    Var1 Var2 Var3
0.5    1    1    0
0.6    0    1    0
0.8    0    0    0
1.1    1    1    1
1.2    0    1    1
1.4    0    0    1

编辑:认为这适用于多个等效变量 - 无法找出没有for循环的方法。我确定Reduce以某种方式可以使用。

认为这给出了正确的结果组合,但如果不是让我知道,因为它已经很晚了,我有点累了。

remove_dups <- function(m, vars) {
  for (k in 1:length(vars)) {
      res <- lapply(split(m, m[, !names(m) %in% vars[[k]]]), function(x, vn=vars[[k]]) {
        x[Reduce(`==`, x[vn]) | cumsum(Reduce(xor, x[vn])) == 1, ]
     })
     m <- do.call(rbind, res)
  }
  m
}

 m <- comb.mat(4)
 remove_dups(m, list(vars=c("Var1", "Var2"), vars=c("Var3", "Var4")))

           Var1 Var2 Var3 Var4
0.0.0.0.16    0    0    0    0
0.0.1.0.12    0    0    1    0
0.0.1.1.4     0    0    1    1
0.1.0.0.14    0    1    0    0
0.1.1.0.10    0    1    1    0
0.1.1.1.2     0    1    1    1
1.1.0.0.13    1    1    0    0
1.1.1.0.9     1    1    1    0
1.1.1.1.1     1    1    1    1