random vector v from uniform distribution at (0,1) with sum(v)=1
10 views (last 30 days)
Show older comments
jimaras
on 14 Mar 2014
Commented: Benjamin Avants
on 15 May 2014
Hello,
How can I generate a uniformly distributed random vector with its sum to be equal to 1?
Thank you
0 Comments
Accepted Answer
John D'Errico
on 14 Mar 2014
Too many people think that generating a uniform sample, then normalizing by the sum will generate a uniform sample. In fact, this is NOT at all true.
A good way to visualize this is to generate that sample for the 2-d case. For example, suppose we do it the wrong way first?
xy = rand(100,2);
plot(xy(:,1),xy(:,2),'.')
Now, lets do the sum projection that virtually everyone poses. (Yes, it is the obvious choice. Now we will see why it is the wrong approach.)
xys = bsxfun(@rdivide,xy,sum(xy,2));
hold on
plot(xys(:,1),xys(:,2),'ro')
axis equal
axis square
The sum-projected points lie along the diagonal line. Note the distribution seems to be biased towards the middle of the line. A uniform sample would have points uniformly distributed along that line.
In a low number of dimensions there are some nice tricks to generate a sample that is indeed uniform. I tend to use Roger Stafford's submission to the file exchange, randfixedsum. It is efficient, and works in any number of dimensions.
figure
xyr = randfixedsum(2,100,1,0,1)';
plot(xyr(:,1),xyr(:,2),'ro')
axis equal
axis square
17 Comments
Matt J
on 15 May 2014
Edited: Matt J
on 15 May 2014
@Ben,
The shape of spoints, when plotted, is not what is germane to the posted topic. The spoints that you've generated is just one vector drawn randomly from the set S={x| sum(x)=1}. The idea of the post is to draw multiple such vectors from S repeatedly and in a uniformly randomized manner (uniformly over S).
Benjamin Avants
on 15 May 2014
If that's the case, I concede the point. I had interpreted the post to be asking for a single vector with uniform distribution and a total sum of 1 derived from a uniform distribution with range (0,1). I was assuming @jimaras was simply asking for a way to convert a uniform distribution (perhaps generated using the rand function) into another uniform distribution with a total sum of 1.
Further, @John stated that my approach does not yield a uniformly distributed result. I suppose this is true if you are trying to maintain uniformity in the (0,1) range, but that did not seem to be his argument. Within the new range of the scaled distribution, I believe I have shown that uniformity is maintained.
I rely on shifting and scaling pseudo-random numbers in some of my work and I felt it was important to understand if my methods were in fact impacting the uniformity of those numbers. So far, it does not seem to be the case.
I appreciate you and @John's willingness to discuss this topic at length.
More Answers (1)
Benjamin Avants
on 14 Mar 2014
You could use rand() to create a uniform distribution then divide each element by the sum.
v = rand(10,1);
vSum = sum(v);
v = v ./ vSum;
3 Comments
Benjamin Avants
on 13 May 2014
John,
Your answer does not explain why my suggestion would not work. Please read my comment on your answer and explain it for me. I would like to understand why this approach is not valid.
John D'Errico
on 14 May 2014
Read my answer, which does show that the simple renormalizing scheme fails to yield a uniform result.
A good way to look at it is if you think of projecting the domain from a square region onto a diagonal straight line crossing the square, you can see that the ends of the line will have fewer points that can contribute to those regions.
Your renormalizing scheme is a terribly common mistake I see made. After all, it is simple, and it seems to get the job done at first glance. It is only when you look more carefully at the actual distribution along the line that people should see it is wrong. Wrong here means non-uniform.
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!