All right that title was terrible but I didn't know what to name it.

Basically I want to make a function that makes an n length vector of random proportions that sum to 1 (100%). I can do it if I know n and fix the function at at certain length of the vector but not if I allow n to be free. I'd really like to use an apply family solution (or non loop if there's some solution I can't for see using neither loop or apply) but if that's not possible a loop is fin (I'd actually like to see both as it'll help with the thinking):

A forced n (works but not what I want

Code:

p <- function(){
v <- sample(seq(0, 1, by=.01), 1)
w <- sample(seq(0, 1-v, by=.01), 1)
x <- sample(seq(0, 1-(v + w), by=.01), 1)
y <- sample(seq(0, 1-(v + w + x), by=.01), 1)
z <- round(1-(v + w + x + y), 2)
c(v, w, x, y, z)
}
p()

an attempt to use global assignment to generate the function I'm actually not sure why this approach doesn't work

Code:

n<-4
y <- 0
sapply(seq_len(n), function(i) {
x <- sample(seq(0, 1-y, by=.01), 1)
y <<- y + x
}
)

Please help again. This is what I got. It spits ot the correct number of proportions but they don't sum to 1. And for n=1 it gives this error:

Code:

p <- function(n){
y <- 0
z <- sapply(seq_len(n-1), function(i) {
x <- sample(seq(0, 1-y, by=.01), 1)
y <<- y + x
return(x)
}
)
w <- c(z ,sample(seq(0, 1-sum(z), by=.01), 1))
return(w)
}

Code:

> p(1)
Error in sum(z) : invalid 'type' (list) of argument

Where as I'd expect it to be 1.

"If you torture the data long enough it will eventually confess."
-Ronald Harry Coase -

p <- function(n){
y <- 0
z <- sapply(seq_len(n-1), function(i) {
x <- sample(seq(0, 1-y, by=.01), 1)
y <<- y + x
return(x)
}
)
w <- c(z , 1-sum(z))
return(w)
}

Still the length zero doesn't work.

"If you torture the data long enough it will eventually confess."
-Ronald Harry Coase -

p <- function(n){
if (n < 2) stop("n must be greater than 1")
y <- 0
z <- sapply(seq_len(n-1), function(i) {
x <- sample(seq(0, 1-y, by=.01), 1)
y <<- y + x
return(x)
}
)
w <- c(z , 1-sum(z))
return(w)
}

Having length 1 is silly anyway. I could do an if else but it makes no sense for the purposes I want this for.

Thanks for the help everybody Sorry for polluting TS with a thread I could have solved if I slowed down a bit but maybe someone will learn from this. The for loop way would still interest me as I want to learn looping better (I know I'll need it as I mope to other languages).

"If you torture the data long enough it will eventually confess."
-Ronald Harry Coase -

Do you necessarily want the stick breaking method to be used to generate your proportions?

Otherwise you could make your life a lot easier...

Code:

n <- 5
# or whatever random number generator you want that only gives positives
tmp <- rgamma(5, 1, 1)
tmp <- tmp/sum(tmp)
# tmp now contains stuff that sums to 1

I don't have emotions and sometimes that makes me very sad.

****, that was gonna be my answer. Just make random numbers, sum them to get a total and then treat each number as a proportion of that total as Dason aptly demonstrated with rgamma. Though, there may be the problem with rounding. I'm assuming the accuracy of this processing isn't that dire, however!

A few hours behind you? Some of us needed to catch up on sleep. Actually, I was walking through my presentation which turned out to be WAY longer than anticipated.