随机数加起来等于100:Matlab

50

我正在将一个人口数量分成不同的矩阵,并希望现在使用随机数来测试我的代码。

大家好,有个快速问题,请提前感谢您的帮助 -

如果我使用;

 100*rand(9,1)

如何让这9个数字相加等于100?

我想要9个在0到100之间的随机数,它们加起来等于100。

是否有内置命令可以实现这个目标,因为我找不到。


1
好问题,但是重复了:与语言相关的部分远不如与语言无关的方面重要。 - Jason S
这个回答解决了你的问题吗?获取N个随机数,它们的和为M - Mahozad
4个回答

96
我经常看到这样的错误:为了生成总和为给定值的随机数,建议只需使用均匀分布的随机数集合并进行缩放。但是如果您以这种方式操作,结果是否真正具有均匀分布呢?
在两个维度上尝试这个简单的测试。生成一个巨大的随机样本,然后将它们缩放为总和为1。我将使用bsxfun来进行缩放。
xy = rand(10000000,2);
xy = bsxfun(@times,xy,1./sum(xy,2));
hist(xy(:,1),100)

如果它们真正是均匀随机的,那么x坐标和y坐标都是均匀的。任何值都有同样的可能性发生。实际上,为了使两个点的总和为1,它们必须位于连接(x,y)平面中的两个点(0,1),(1,0)的直线上。为了使这些点均匀分布,该直线上的任何一点都必须具有相等的可能性。

xy histogram

明显,在使用缩放方案时,统一性失败了。该线上的任何点都不是同等可能的。我们可以看到在三维中发生了相同的事情。在这里的三维图形中,三角区域中心的点更密集地分布。这反映了不均匀性。
xyz = rand(10000,3);
xyz = bsxfun(@times,xyz,1./sum(xyz,2));
plot3(xyz(:,1),xyz(:,2),xyz(:,3),'.')
view(70,35)
box on
grid on

xyzplot

再次强调,简单的缩放解决方案失败了。它不能在感兴趣的区域内产生真正均匀的结果。

我们能做得更好吗?答案是肯定的。在二维平面中,一种简单的解决方案是生成一个随机数,表示沿着连接点(0,1)和(1,0)的直线的距离。

t = rand(10000000,1);
xy = t*[0 1] + (1-t)*[1 0];
hist(xy(:,1),100)

Uniform x+y = 1

可以证明,在单位正方形上,由方程x+y=1定义的直线上的任何点现在被等概率地选择。这通过漂亮的平坦直方图反映出来。
David Schwartz建议的排序技巧在n维中是否有效?显然在2维中是有效的,下面的图表表明在3维中也是有效的。没有深入思考这个问题,我相信它将在n维的基本情况下起作用。
n = 10000;
uv = [zeros(n,1),sort(rand(n,2),2),ones(n,1)];
xyz = diff(uv,[],2);

plot3(xyz(:,1),xyz(:,2),xyz(:,3),'.')
box on
grid on
view(70,35)

Sort trick

您还可以从文件交换中下载 randfixedsum 函数,这是 Roger Stafford 贡献的一个更通用的解决方案,可以在单位超立方体内生成具有任何给定固定和的真正均匀的随机集合。因此,要生成在单位 $3$ 立方体中的点集,使其满足总和为 $1.25$ 的约束条件...

xyz = randfixedsum(3,10000,1.25,0,1)';
plot3(xyz(:,1),xyz(:,2),xyz(:,3),'.')
view(70,35)
box on
grid on

randfixedsum


1
我知道这已经是一个老问题了,但有人能解释一下这个答案吗?如何“生成一个单一的随机数,指定连接点(0,1)和(1,0)之间线段上的距离。可以证明,在单位正方形中由方程x + y = 1定义的任何点现在都可能被选择。”?这甚至准确吗?我困惑的部分是他为证明所贴的Matlab代码只显示随机数是均匀的,然而它们并没有按比例缩放到1......这才是重点。 - jdfinch3
1
@jdfinch3:正在解决的问题是“选择一对数字x,y,使得x+y=1。” 解决方案是:“在范围[0,1]中选择x,然后计算y = 1-x”。这确保了从所有可能的对组成的宇宙中均匀选择对(x,y)。直方图证明它有效。David Schwartz的答案为超过两个维度(即具有两个以上元素的元组)提供了一般化。 - rici
@rici - 感谢您的回复!您对解决方案的重新表述让我恍然大悟。 :) - jdfinch3
证明三维情况相对容易:设两个随机数为p和q,如果p < q,则(p,q)位于三角形(0,0)-(0,1)-(1,1)内,如果p > q,则(q,p)位于该三角形内。从1中减去较大的数字将三角形映射到(0,1)-(0,0)-(1,0),这是所需区域在xy平面上的投影,z就是所需的p和q之间的差异。对于更高的维度,我认为你可以在N-D超立方体中放置N个N-D超金字塔的事实意味着排序第N个随机数等同于选择一个合适的超金字塔。 - Neil

75

一种简单的方法是从0到100之间随机选取8个数字,将0和100添加到列表中,得到10个数字。然后对它们进行排序。接着输出相邻两个数字之间的差值。例如,这里是8个在0到100之间随机选取的数字:

96、38、95、5、13、57、13、20

所以添加0和100并排序。

0、5、13、13、20、38、57、95、96、100

现在做减法:

5-0 = 5
13-5 = 8
13-13 = 0
20-13 = 7
38-20 = 18
57-38 = 19
95-57 = 38
96-95 = 1
100-96 = 4

这样就得出了九个数字,它们的和为100:0、1、4、5、7、8、18、19、38。我得到一个零和一个一只是奇怪的运气而已。


4
太棒了!我喜欢它。我已经采用了你的方法创建了一系列随机数,它们加起来为0。这使得我可以创建没有效应的随机变化(例如:一个移动的游戏精灵看起来似乎在随机移动,但从未超出屏幕。^^)。 - Timo
8
只有在允许使用0到总和之间的任意随机数时,此方法才有效!例如,如果随机数的范围小于所需的总和,则此方法不起作用。 - Behrooz
3
这个方法是可行的,但这个答案可能需要再编辑一下……这里有8个数字列表……加上0和100(并从列表中默默删除20以使得总数为9个数字)。该答案以“总计为100的九个数字:”结束,并继续列出八个数字。通常趋势是将N个数字的列表创建成一个由插入0和100组成的N+2数字列表,将它们相减至N+1个数字并对结果进行排序。 - surgical_tubing
1
@surgical:我修复了这个例子,我认为只是一个简单的错误。我认为对最终元组进行排序是具有误导性的,但我会让原作者决定。 - rici
Python示例:
a = [0] + sorted([random.random()*100 for _ in range(9-1)]) + [100] b = [a[i+1] - a[i] for i in range(len(a)-1)] sum(b) == 100
- Doody P
如果一些约束条件不是恒定的,而是其他随机变量的函数,比如a2的限制器是a1/2,你会如何处理?(即a2最多只能是a1的一半,并假设这些约束条件中没有循环) - Veltzer Doron

6

现在给出正确的答案还不算太晚。

我们来谈谈在区间[0...1]内对X1...XN进行抽样,使得Sum(X1, ..., XN)等于1。然后你可以将它重新缩放到100。

这被称为Dirichlet分布,下面是从中抽样的代码。最简单的情况是所有参数都等于1,那么X1, ..., XN的所有边际分布将是U(0,1)。在一般情况下,具有与1不同的参数的边际分布可能会有峰值。

----------------- 取自这里 ---------------------

Dirichlet是单位规模伽马随机变量向量,通过它们的总和归一化。所以,没有错误检查,这将为您提供:

a = [1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0]; // 9 numbers to sample
n = 10000;
r = drchrnd(a,n)

function r = drchrnd(a,n)
  p = length(a);
  r = gamrnd(repmat(a,n,1),1,n,p);
  r = r ./ repmat(sum(r,2),1,p);

1

取一个由N-1个数字组成的列表,通过插入0和100创建一个由N+1个数字组成的列表,对列表进行排序,并将它们差分到总数为N的数字。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接