Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate combinations of values which sum to one, sorted in descending order

Tags:

r

Do you know a more efficient way to generate a matrix holding all unique combinations of "weights" (let weights be w and 0 <= w <= 1, and values of w are separated by steps of 0.1), such that the weights sum to one AND the first is the highest, the last the lowest weight.

Here is code that does the job, but it seems inefficient to delete rows:

# generate combinations of weights such that w1 >= w2 >= w3 ...
w = seq(0, 1, 0.1) #weights 0, 0.1, ..., 0.9, 1
w = expand.grid(w, w, w, KEEP.OUT.ATTRS = FALSE) #all combinations of 3 weights
w = w[rowSums(w) == 1, ] #make sure the weights sum to one
w = w[!(w[, 1] < w[, 2] | w[, 2] < w[, 3]),] #make sure w1 >= w2 >= w3 ...

w    
#     Var1 Var2 Var3
# 11   1.0  0.0  0.0
# 21   0.9  0.1  0.0
# 31   0.8  0.2  0.0
# 41   0.7  0.3  0.0
# 51   0.6  0.4  0.0
# 61   0.5  0.5  0.0
# 141  0.8  0.1  0.1
# 151  0.7  0.2  0.1
# 171  0.5  0.4  0.1
# 271  0.6  0.2  0.2
# 281  0.5  0.3  0.2
# 291  0.4  0.4  0.2
# 401  0.4  0.3  0.3

Let me add some more general info: In this problem (3 weights in the above order) the upper limits for the first, second, third values are as follows:

  • the first number can minimally be 1 for the combination (1, 0, 0)
  • the second number can maximally be 1/2 for the combination (1/2, 1/2, 0)
  • the third number can maximally be 1/3 for the combination (1/3, 1/3, 1/3)
like image 450
JBJ Avatar asked Jul 28 '15 09:07

JBJ


2 Answers

A non-base possibility:

library(partitions)

step <- 0.1
n_weights <- 3

t(restrictedparts(n = 1/step, m = n_weights) * step)
#  [1,] 1.0 0.0 0.0
#  [2,] 0.9 0.1 0.0
#  [3,] 0.8 0.2 0.0
#  [4,] 0.7 0.3 0.0
#  [5,] 0.6 0.4 0.0
#  [6,] 0.5 0.5 0.0
#  [7,] 0.8 0.1 0.1
#  [8,] 0.7 0.2 0.1
#  [9,] 0.6 0.3 0.1
# [10,] 0.5 0.4 0.1
# [11,] 0.6 0.2 0.2
# [12,] 0.5 0.3 0.2
# [13,] 0.4 0.4 0.2
# [14,] 0.4 0.3 0.3
like image 173
Henrik Avatar answered Nov 04 '22 06:11

Henrik


General purpose function with standard packages:

# Generate weights matrix with noWeights columns and noRows rows.
# Each row of this matrix contains sorted decremental weights summing up to 1.0.
generateWeights = function(noWeights,
                           noRows,
                           distribution = runif,
                           rounding = function(x){ round(x, 1) })
{
  generator = function()
  {
    x = distribution (noWeights);
    x = x/sum(x);
    sort(rounding(x), decreasing = T)
  } 
  t(replicate(noRows, generator()))
}

# example of use
generateWeights(3, 10)
like image 20
Yester Avatar answered Nov 04 '22 06:11

Yester