Search code examples
rconstraintscombinationsaggregation

Combinations with constraints


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:

  1. All 3 groups must be represented (e.g. 1,2,2,2,2 is not accepted since 3 is missing)
  2. 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)

Solution

  • 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