I would like to generate all possible combinations with some constraints but I can't find a smart solution.
Suppose I have 5 element order by riskiness and I want combine these elements in three aggregate groups with these constraints:
- All 3 groups must be represented (e.g. 1,2,2,2,2 is not accepted since 3 is missing)
- Order matters (e.g. 1,2,1,2,3 is not accepted because 1 is between the two)
At the moment I create these groups with these line of codes, but I would like to extend to multi cases (e.g. 15 element aggregated in 5 groups etc.). Is there a R function already available?
risk_disaggregated<-c("1. Very low risk","2. Low risk","3. Medium risk","4. High risk","5. Very high risk")
aggregation<-c(rep(1,3),rep(2,1),rep(3,1))
aggregation1<-c(rep(1,1),rep(2,3),rep(3,1))
aggregation2<-c(rep(1,1),rep(2,1),rep(3,3))
aggregation3<-c(rep(1,1),rep(2,2),rep(3,2))
aggregation4<-c(rep(1,2),rep(2,2),rep(3,1))
aggregation5<-c(rep(1,2),rep(2,1),rep(3,2))
db_final<-cbind(risk_disaggregated,aggregation,aggregation1,aggregation2,aggregation3,aggregation4,aggregation5)
CodePudding user response:
I came up with this:
library(dplyr) # bind_cols
risk_disaggregated<-c("1. Very low risk",
"2. Low risk",
"3. Medium risk",
"4. High risk",
"5. Very high risk")
unique_vals <- 1:3
fill <- 5
most <- fill-length(unique_vals)
(variations <- combn(x = rep(unique_vals,most),
m = most,
simplify = FALSE) |>
lapply(sort) |>
unique())
(variations <- setNames(variations,
paste0("set_",seq_along(variations))))
bind_cols(risk=risk_disaggregated,
lapply(variations,\(x)sort(c(unique_vals,x))))
CodePudding user response:
Since each row of n
elements must have at least one entry of each of k
groups, simply cbind
a matrix where every row is 1:k
with a matrix of combinations of 1:(n - k)
with repetition. Then sort each row to meet your order constraint.
An implementation using RcppAlgos
and Rfast
. It will be quite fast.
library(RcppAlgos) # for comboGeneral
library(Rfast) # for rowSort
k <- 3L
n <- 5L
rowSort(cbind(m <- comboGeneral(k, n - k, TRUE), col(diag(0L, nrow(m), k))))
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 1 1 1 2 3
#> [2,] 1 1 2 2 3
#> [3,] 1 1 2 3 3
#> [4,] 1 2 2 2 3
#> [5,] 1 2 2 3 3
#> [6,] 1 2 3 3 3
The 15 element, 5 group case:
k <- 5L
n <- 15L
m <- rowSort(cbind(m <- comboGeneral(k, n - k, TRUE), col(diag(0L, nrow(m), k))))
dim(m)
#> [1] 1001 15