问题
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