R - generate all possible pairwise combinations of binary vectors

╄→гoц情女王★ 提交于 2019-12-12 15:11:52

问题


I am looking for a smart way to generate all pairwise combinations of two vectors of length n, where only one value is not zero.

For now I am doing something quite desperate with loops through each combination with: n <- 3; z <- rep(0,n); m <- apply(combn(1:n,1),2,function(k) {z[k]=1;z}) but there must be a better way without loops?

This is what I'm after for example for n=3:

     [,1] [,2] [,3]
[1,]    1    0    0
[2,]    0    1    0  

[1,]    1    0    0
[2,]    0    0    1

[1,]    0    1    0
[2,]    1    0    0

[1,]    0    1    0
[2,]    0    0    1

[1,]    0    0    1
[2,]    1    0    0

[1,]    0    0    1
[2,]    0    1    0

Thanks so much for the help.


回答1:


Something like this?

n <- 3
g <- 2 # g must be < n 
m <- combn(n, g)
mm <- as.numeric(m)
mat <- matrix(0, nrow = g * ncol(m), ncol = n)
mat[ cbind(1:nrow(mat), mm)] <- 1

mat
#       [,1] [,2] [,3]
#[1,]    1    0    0
#[2,]    0    1    0

#[3,]    1    0    0
#[4,]    0    0    1

#[5,]    0    1    0
#[6,]    0    0    1

# mat is half the answer :)
# the other half is
mat[nrow(mat):1, ]

#      [,1] [,2] [,3]
#[1,]    0    0    1
#[2,]    0    1    0

#[3,]    0    0    1
#[4,]    1    0    0

#[5,]    0    1    0
#[6,]    1    0    0

soln <- rbind(mat, mat[nrow(mat):1, ])

# as suggested by the OP to split the soln 
d <- split(data.frame(soln), rep(1:(nrow(soln)/g), each=g))



回答2:


The astute reader will notice that the question can be reduced to: "How to generate all pairwise permutations of powers of 2?" By viewing it this way, we can avoid initially dealing with binary vectors and save this for the last step.

Using the base R function intToBits, this answer to the question How to convert integer numbers into binary vector?, and any function that can generate permutation of a specific length (There are many packages for this: gtools::permutations, RcppAlgos::permuteGeneral, iterpc, and arrangements::permutations), we can obtain the desired result in one line.

library(gtools)
t(sapply(t(gtools::permutations(3, 2, 2^(0:2))),  
         function(x) {as.integer(intToBits(x))})[1:3, ])

      [,1] [,2] [,3]
 [1,]    1    0    0
 [2,]    0    1    0

 [3,]    1    0    0
 [4,]    0    0    1

 [5,]    0    1    0
 [6,]    1    0    0

 [7,]    0    1    0
 [8,]    0    0    1

 [9,]    0    0    1
[10,]    1    0    0

[11,]    0    0    1
[12,]    0    1    0

Generalizing is easy.

bitPairwise <- function(numBits, groupSize) {
    t(sapply(t(gtools::permutations(numBits, groupSize, 2^(0:(numBits-1)))), 
                 function(x) {as.integer(intToBits(x))})[1:numBits, ])
}

 bitPairwise(numBits = 6, groupSize = 3)[1:12, ]
      [,1] [,2] [,3] [,4] [,5] [,6]
 [1,]    1    0    0    0    0    0
 [2,]    0    1    0    0    0    0
 [3,]    0    0    1    0    0    0

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

 [7,]    1    0    0    0    0    0
 [8,]    0    1    0    0    0    0
 [9,]    0    0    0    0    1    0

[10,]    1    0    0    0    0    0
[11,]    0    1    0    0    0    0
[12,]    0    0    0    0    0    1


UPDATE

I'm only posting this to point out how @Suren's answer could be made correct.

The OP is looking for permutations not combinations

From the conversation in the comments, you will see that @Suren's solution does not give correct results when the number of groups increases ("I am also trying to get groupings of three instead of 2 (or any number)" and "This is cutting off some solutions").

It appears that @Suren's answer gives correct results with g = 2. This is so, because the permutations of 1:n choose 2 is equal to the combinations of 1:n choose 2 combined with the combinations of n:1 choose 2 (notice that 1:n is reversed). This is precisely what @Suren's answer is doing (i.e. generate combinations choose 2, write them in reverse order, and combine).

## original version
surenFun <- function(n, g) {
    m <- combn(n, g)
    mm <- as.numeric(m)
    mat <- matrix(0, nrow = g * ncol(m), ncol = n)
    mat[ cbind(1:nrow(mat), mm)] <- 1
    soln <- rbind(mat, mat[nrow(mat):1, ])
    split(data.frame(soln), rep(1:(nrow(soln)/g), each=g))
}

## Here is the corrected version
surenFunCorrected <- function(n, g) {
    ## changed combn to gtools::permutations or any other
    ## similar function that can generate permutations
    m <- gtools::permutations(n, g)
    ## you must transpose m
    mm <- as.numeric(t(m))
    ## change ncol(m) to nrow(m)
    mat <- matrix(0, nrow = g * nrow(m), ncol = n)
    mat[ cbind(1:nrow(mat), mm)] <- 1
    ## removed soln
    split(data.frame(mat), rep(1:(nrow(mat)/g), each=g))
}

With the given example from the OP, it gives the same result just in a different order:

## The order is slightly different
match(surenFunCorrected(3, 2), surenFun(3, 2))
[1] 1 2 6 3 5 4

all(surenFunCorrected(3, 2) %in% surenFun(3, 2))
[1] TRUE

all(surenFun(3, 2) %in% surenFunCorrected(3, 2))
[1] TRUE

Let's test this with g = 3 and n = 4.

## N.B. all of the original output is
## contained in the corrected output
all(surenFun(4, 3) %in% surenFunCorrected(4, 3))
[1] TRUE

## However, there are 16 results
## not returned in the original
leftOut <- which(!(surenFunCorrected(4, 3) %in% surenFun(4, 3)))
leftOut
[1]  3  5  6  7  8  9 11 12 13 14 16 17 18 19 20 22

## E.g. 3 examples that were left out
surenFunCorrected(4, 3)[leftOut[c(1,8,16)]]
$`3`
  X1 X2 X3 X4
7  1  0  0  0
8  0  0  1  0
9  0  1  0  0

$`12`
   X1 X2 X3 X4
34  0  1  0  0
35  0  0  0  1
36  0  0  1  0

$`22`
   X1 X2 X3 X4
64  0  0  0  1
65  0  1  0  0
66  0  0  1  0


来源:https://stackoverflow.com/questions/48292795/r-generate-all-possible-pairwise-combinations-of-binary-vectors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!