Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate m equally-spaced numbers that sum to 1 in R

Tags:

r

Given m, how we can generate m equally-spaced numbers that sum to 1 such that A1 > A2 > ... > Am?

For example, if m=4 then we should have:

a <- c(0.4, 0.3, 0.2, 0.1)

abs(diff(a))
#[1] 0.1 0.1 0.1

sum(a)
#[1] 1

Or for m=5:

b <- c(0.30, 0.25, 0.20, 0.15, 0.10)

abs(diff(b))
#[1] 0.05 0.05 0.05 0.05

sum(b)
#[1]
like image 961
989 Avatar asked Nov 18 '16 15:11

989


2 Answers

How about:

rev(seq_len(m)/sum(seq_len(m)))

a <- rev(seq_len(4)/sum(seq_len(4)))
##[1] 0.4 0.3 0.2 0.1
abs(diff(a))
##[1] 0.1 0.1 0.1
sum(a)
##[1] 1

b <- rev(seq_len(5)/sum(seq_len(5)))
##[1] 0.33333333 0.26666667 0.20000000 0.13333333 0.06666667
abs(diff(b))
##[1] 0.06666667 0.06666667 0.06666667 0.06666667
sum(b)
##[1] 1
like image 162
aichao Avatar answered Sep 21 '22 22:09

aichao


If you want an adjustable space or starting point, you can use a formula to calculate the space based on starting point or the starting point based on the space:

Scenario 1: Adjustable starting point:

m = 5; s = 0.9

seq(from = s, by = -(m*s - 1) * 2/((m - 1) * m), length.out = m)
#[1]  0.90  0.55  0.20 -0.15 -0.50

sum(seq(from = s, by = -(m*s - 1) * 2/((m - 1) * m), length.out = m))
#[1] 1

Scenario 2: Adjustable space:

m = 5; d = 0.2

seq(from = 1/m + ((m - 1) * d/2), by = -d, length.out = m)
# [1]  0.6  0.4  0.2  0.0 -0.2

sum(seq(from = 1/m + ((m - 1) * d/2), by = -d, length.out = m))
# [1] 1
like image 40
Psidom Avatar answered Sep 17 '22 22:09

Psidom