JBJ
JBJ

Reputation: 876

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

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:

Upvotes: 8

Views: 642

Answers (2)

Henrik
Henrik

Reputation: 67778

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

Upvotes: 4

Yester
Yester

Reputation: 683

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)

Upvotes: 1

Related Questions