我想获取N个随机数,它们的总和为一个给定的值。
例如,假设我想要5个随机数,它们的总和为1。
那么,一个有效的可能性是:
0.2 0.2 0.2 0.2 0.2
另一个可能性是:
0.8 0.1 0.03 0.03 0.04
等等。我需要这个来创建模糊C均值的所有物矩阵。
我想获取N个随机数,它们的总和为一个给定的值。
例如,假设我想要5个随机数,它们的总和为1。
那么,一个有效的可能性是:
0.2 0.2 0.2 0.2 0.2
另一个可能性是:
0.8 0.1 0.03 0.03 0.04
等等。我需要这个来创建模糊C均值的所有物矩阵。
简短回答:
生成N个随机数,计算它们的总和,将每个随机数除以总和并乘以M。
详细回答:
上述方法不会产生均匀分布,这可能是根据这些随机数用途的问题。Matti Virkkunen提出了另一种方法:
在0到1之间生成N-1个随机数,在列表中添加数字0和1本身,对它们进行排序,并取相邻数字的差。
如此处所解释的那样,这会产生均匀分布。
生成 N-1 个介于0和1之间的随机数,将数字0和1加入列表中,对列表进行排序,并取相邻数字的差。
N
个变量都是由相同的概率密度函数 f(x) = M^(1 - N) (-1 + N) (M - x)^(-2 + N)
绘制的。请注意,它的平均值为 M/N
,符合预期。 - Sungmin值得注意的是目前被接受的答案并不能给出均匀分布:
"只需生成N个随机数,计算它们的和,再将每个数除以总和"
让我们看一个当N=2且M=1的简单情况。这是一个微不足道的例子,因为我们可以生成一个列表[x,1-x],其中选择x在范围(0,1)内均匀分布。所提出的解决方案生成一对[x/(x+y),y/(x+y)],其中x和y在(0,1)上均匀分布。为了分析这个问题,我们选择一些z,使得0<z<0.5,并计算第一个元素小于z的概率。如果分布是均匀的,则该概率应为z。然而,我们得到
Prob(x/(x+y) < z) = Prob(x < z(x+y)) = Prob(x(1-z) < zy) = Prob(x < y(z/(1-z))) = z/(2-2z).
我进行了一些快速计算,发现目前唯一能够导致均匀分布的解决方案是由Matti Virkkunen提出的:
"生成0到1之间的N-1个随机数,将0和1本身添加到列表中,排序,然后取相邻数字之差。"
x
,然后将其除以 sqrt(x)
,结果就不是均匀分布的。 - Steve Jessop很不幸,这里的一些答案如果您想要均匀随机数是错误的。保证统一随机数最简单(在许多语言中也是最快)的解决方案只需要:
# This is Python, but most languages support the Dirichlet.
import numpy as np
np.random.dirichlet(np.ones(n))*m
其中n
是您想要生成的随机数的数量,m
是生成数组的总和。这种方法产生正值,并且特别适用于生成总和为1的有效概率(让m = 1)。
Generate N exponentially-distributed random variates. One way to generate such a number can be written as—
number = -ln(1.0 - RNDU())
where ln(x)
is the natural logarithm of x
and RNDU()
is a method that returns a uniform random variate greater than 0 and less than 1. Note that generating the N variates with a uniform distribution is not ideal because a biased distribution of random variate combinations will result. However, the implementation given above has several problems, such as being ill-conditioned at large values because of the distribution's right-sided tail, especially when the implementation involves floating-point arithmetic. Another implementation is given in another answer.
Divide the numbers generated this way by their sum.
Multiply each number by M.
n
个随机整数,这些整数相加得到一个整数m * x
,并将这些整数视为分母为x
的n
个有理数的分子(假设m
是整数,则它们将总和为m
)。您可以选择x
为大数,如2的32次方或2的64次方,或其他具有所需精度的数字。如果x
为1且m
是整数,则解决了生成随机整数总和为m
的问题。
METHOD PositiveIntegersWithSum(n, m)
if n <= 0 or m <=0: return error
ls = [0]
ret = NewList()
while size(ls) < n
c = RNDINTEXCRANGE(1, m)
found = false
for j in 1...size(ls)
if ls[j] == c
found = true
break
end
end
if found == false: AddItem(ls, c)
end
Sort(ls)
AddItem(ls, m)
for i in 1...size(ls): AddItem(ret,
ls[i] - ls[i - 1])
return ret
END METHOD
METHOD IntegersWithSum(n, m)
if n <= 0 or m <=0: return error
ret = PositiveIntegersWithSum(n, m + n)
for i in 0...size(ret): ret[i] = ret[i] - 1
return ret
END METHOD
RNDINTEXCRANGE(a, b)
返回一个在区间 [a, b) 中均匀分布的随机整数。在Java中:
private static double[] randSum(int n, double m) {
Random rand = new Random();
double randNums[] = new double[n], sum = 0;
for (int i = 0; i < randNums.length; i++) {
randNums[i] = rand.nextDouble();
sum += randNums[i];
}
for (int i = 0; i < randNums.length; i++) {
randNums[i] /= sum * m;
}
return randNums;
}
randNums[i] /= sum * m;
相当于 randNums[i] = randNums[i] / (sum * m);
。但是需要修改为 randNums[i] = randNums[i] / sum * m;
,以确保运算顺序正确。 - Bill the Lizardpublic static double[] getRandDistArray(int n, double m)
{
double randArray[] = new double[n];
double sum = 0;
// Generate n random numbers
for (int i = 0; i < randArray.length; i++)
{
randArray[i] = Math.random();
sum += randArray[i];
}
// Normalize sum to m
for (int i = 0; i < randArray.length; i++)
{
randArray[i] /= sum;
randArray[i] *= m;
}
return randArray;
}
getRandDistArray(5, 1.0)
返回了以下内容:[0.38106150346121903, 0.18099632814238079, 0.17275044310377025, 0.01732932296660358, 0.24786240232602647]
现在你有N个随机数,它们的总和是期望的总和。
你的限制条件有点少。很多程序都可以工作。
例如,数字是否服从正态分布?均匀分布?
我假设所有数字必须是正数,并且围绕平均值M/N均匀分布。
试试这个。