All possible combination of binary matrix with constraint
We want to describe all possible combinations of mappings (interactions) between stores (rows) and products (columns). In the interaction matrix, an interaction is encoded by 1
, its absence by 0
. The constraint is that the column and row sum are greater equal 1
.
This is an interesting combinatorics question; my approach by enumerating all possible combinations is not very efficient; I'm sure there are much more efficient implementations that take into account possible symmetries of the matrices. It'd be interesting to see other solutions...
In the following, I make use of function gtools::permutations
.
matrixCombn <- function(nrow, ncol) {
# All possible column combinations for a matrix of dimension dim
# Here we assume two different values c(1, 0)
require(gtools);
columns <- t(permutations(n = 2, r = nrow, v = c(1, 0), repeats.allowed = TRUE));
columns <- columns[, colSums(columns) > 0];
# Construct all possible combinations of dim column vectors and
# impose constraint that row and column sum >= 1
ret <- lapply(as.data.frame(t(permutations(ncol(columns), ncol, repeats.allowed = TRUE))), function(x) {
m.cand <- columns[, x];
if (all(rowSums(m.cand) > 0) & all(colSums(m.cand) > 0)) m.cand else NULL;
})
ret <- Filter(Negate(is.null), ret);
return(ret);
}
# Example for 3x3 interaction matrix design
ret <- matrixCombn(3, 3);
This gives us 265 unique combinations
length(ret);
# [1] 265
For example, here are the first 3
ret[1:3];
#$V6
# [,1] [,2] [,3]
#[1,] 0 0 1
#[2,] 0 0 1
#[3,] 1 1 0
#$V7
# [,1] [,2] [,3]
#[1,] 0 0 1
#[2,] 0 0 1
#[3,] 1 1 1
#$V11
# [,1] [,2] [,3]
#[1,] 0 0 1
#[2,] 0 1 0
#[3,] 1 0 0
For a 3x2
interaction matrix design we get
ret <- matrixCombn(3, 2);
length(ret);
# [1] 25
with the first 3 combinations
ret[1:3];
#$V6
# [,1] [,2]
#[1,] 0 1
#[2,] 0 1
#[3,] 1 0
#$V7
# [,1] [,2]
#[1,] 0 1
#[2,] 0 1
#[3,] 1 1
#$V12
# [,1] [,2]
#[1,] 0 1
#[2,] 1 0
#[3,] 0 1
Random unique binary matrices
I suggest you just generate the matrices completely random and check for each new matrix if it already has been created. If not, discard it.
As long as the number of possible matrices is a lot bigger than the number of matrices needed this works well, otherwise it may be slow.
Example code:
randomMatrix <- function(n) matrix(as.numeric(runif(n^2) > 0.5), ncol = n) # generates random binary square matrix of size n x n
m <- 1000 # number of matrices needed
res <- vector("list", m) # stores the result
i <- 1 # index of next matrix
while (i <= m) {
cand <- randomMatrix(5)
## check if the candidate is distinct from all matrices in res
if (!any(sapply(res, function(x) identical(x, cand)))) {
res[[i]] <- cand
i <- i + 1
}
}
If you really run into speed problems (which I doubt) you could use some hashes to speed up compoarison. For example you could store the row- and column sums for each matrix and only test for equality if the sums coincide.
Create combinations of a binary vector
A slightly faster version of Marat's answer:
f.roland <- function(n, m) {
ind <- combn(seq_len(n), m)
ind <- t(ind) + (seq_len(ncol(ind)) - 1) * n
res <- rep(0, nrow(ind) * n)
res[ind] <- 1
matrix(res, ncol = n, nrow = nrow(ind), byrow = TRUE)
}
all.equal(f.2(16, 8), f.roland(16, 8))
#[1] TRUE
library(rbenchmark)
benchmark(f(16,8),f.2(16,8),f.roland(16,8))
# test replications elapsed relative user.self sys.self user.child sys.child
#2 f.2(16, 8) 100 5.693 1.931 5.670 0.020 0 0
#3 f.roland(16, 8) 100 2.948 1.000 2.929 0.017 0 0
#1 f(16, 8) 100 8.287 2.811 8.214 0.066 0 0
Combinations of binary values in r
Some sample data:
n <- 10
dat <- data.frame(A = sample(0:1, n, replace = TRUE),
B = sample(0:1, n, replace = TRUE),
C = sample(0:1, n, replace = TRUE),
D = sample(0:1, n, replace = TRUE))
A function that given a number of columns to combine, computes all combinations and corresponding sums:
count.or <- function(dat, n = 2) {
or.sum <- function(cols) sum(rowSums(dat[cols]) > 0)
counts <- combn(colnames(dat), n, FUN = or.sum)
names <- combn(colnames(dat), n, FUN = paste, collapse = "")
setNames(counts, names)
}
In action:
count.or(dat, 1)
# A B C D
# 6 6 5 9
count.or(dat, 2)
# AB AC AD BC BD CD
# 8 7 9 9 10 9
count.or(dat, 3)
# ABC ABD ACD BCD
# 9 10 9 10
count.or(dat, 4)
# ABCD
# 10
Or in one call:
unlist(lapply(1:4, count.or, dat = dat))
# A B C D AB AC AD BC BD CD ABC ABD ACD BCD ABCD
# 6 6 5 9 8 7 9 9 10 9 9 10 9 10 10
R: Get all combinations of p binary variables
OK, found it:
p <- 3
l <- rep(list(0:1), p)
expand.grid(l)
From here:
Generate list of all possible combinations of elements of vector
R - generate all possible pairwise combinations of binary vectors
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))
How to create a matrix from all possible combinations of 2 or more matrices?
You can use expand.grid()
and take its output to index the matrix A and B,
x <- expand.grid(1:3,1:3)
cbind(A[x[,1],], B[x[,2],])
gives,
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 0 0 1 0 0
[2,] 0 1 0 0 1 0
[3,] 0 0 1 0 0 1
[4,] 1 0 0 1 0 0
[5,] 0 1 0 0 1 0
[6,] 0 0 1 0 0 1
[7,] 1 0 0 1 0 0
[8,] 0 1 0 0 1 0
[9,] 0 0 1 0 0 1
EDIT:
For more than two matrices, you can use a function like below,
myfun <- function(...) {
arguments <- list(...)
a <- expand.grid(lapply(arguments, function(x) 1:nrow(x)))
do.call(cbind,lapply(seq(a),function(x) { arguments[[x]][a[,x],] }))
}
out <- myfun(A,B,C)
head(out)
gives,
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 0 0 1 0 0 1 0 0 0
[2,] 0 1 0 1 0 0 1 0 0 0
[3,] 0 0 1 1 0 0 1 0 0 0
[4,] 1 0 0 0 1 0 1 0 0 0
[5,] 0 1 0 0 1 0 1 0 0 0
[6,] 0 0 1 0 1 0 1 0 0 0
Data:
A <- B <- diag(3)
C <- diag(4)
Related Topics
Ggplot2: Making Changes to Symbols in The Legend
Merge Data Based on Nearest Date R
Removing "Nul" Characters (Within R)
Heatmap with Values and Some Additional Features in R
Plot Histogram with Points Instead of Bars
Line Segments or Rectangles with Hover Information in R Plotly Figure
Trouble Getting Latest Version of Gdal on Ubuntu Running R
Make a Column with Duplicated Values Unique in a Dataframe
Converting a Long-Formated Dataframe to Wide Format Tidyverse
Inserting Logo into Beamer Presentation Using R Markdown
How to Filter Cases in a Data.Table by Multiple Conditions Defined in Another Data.Table
Ggplot2 Equivalent of 'Factorization or Categorization' in Googlevis in R
Generating Dropdown Menu for Plotly Charts
Ggplot2: How to Separate Geom_Polygon and Geom_Line in Legend Keys