Skip to content

How to draw 4 random weights that sum up to 1?

5 messages · Alexander Engelhardt, Uwe Ligges, David Winsemius +1 more

#
Hey list,

This might be a more general question and not that R-specific. Sorry for 
that.

I'm trying to draw a random vector of 4 numbers that sum up to 1.
My first approach was something like

   a <- runif(1)
   b <- runif(1, max=1-a)
   c <- runif(1, max=1-a-b)
   d <- 1-a-b-c

but this kind of distorts the results, right?
Would the following be a good approach?

   w <- sample(1:100, 4, replace=TRUE)
   w <- w/sum(w)

I'd prefer a general algorithm-kind of answer to a specific R function 
(if there is any). Although a function name would help too, if I can 
sourcedive.

Thanks in advance,
  Alex
#
You probably want to generate data from a Dirichlet distribution.  There are some functions in packages that will do this and give you more background, or you can just generate 4 numbers from an exponential (or gamma) distribution and divide them by their sum.
#
On 10.10.2011 18:10, Alexander Engelhardt wrote:
Yes, although better combine both ways to

w <- runif(4)
w <- w / sum(w)

Uwe Ligges
#
On Oct 10, 2011, at 12:44 PM, Uwe Ligges wrote:

            
For the non-statisticians in the audience like myself who didn't know  
what that distribution might "look like" (it being difficult to  
visualize densities on your 3-dimensional manifold in 4-space),  here  
is my effort to get an appreciation:

  M4 <- matrix(runif(40000), ncol=4)
  M4 <- M4/rowSums(M4)
# just a larger realization of Ligges' advice
  colMeans(M4)
[1] 0.2503946 0.2499594 0.2492118 0.2504342
  plot(density(M4[,1]))
  lines(density(M4[,2]),col="red")
  lines(density(M4[,3]),col="blue")
  lines(density(M4[,4]),col="green")

plot(density(rowSums(M4[,1:2])))

  plot(density(rowSums(M4[,1:3])))
plot(density(rowSums(M4[,2:4])))

# rather kewl results, noting that these are a reflecion around 0.5 of  
the single vector densities.

  
    
#
As an interesting extension to David's post, try:

M4.e <- matrix(rexp(40000,1), ncol=4)

Instead of the uniform and rerun the rest of the code (note the limits on the x-axis).

With 3 dimensions and the restriction we can plot in 2 dimensions to compare:

library(TeachingDemos)

m3.unif <- matrix(runif(3000),  ncol=3)
m3.unif <- m3.unif/rowSums(m3.unif)

m3.exp  <- matrix(rexp(3000,1), ncol=3)
m3.exp  <- m3.exp/rowSums(m3.exp)


dev.new()
triplot(m3.unif)

dev.new()
triplot(m3.exp)

now compare the 2 plots on the density of the points near the corners.