之前已经问过这个问题,但我从来没有真正看到过这么好的答案。
我想生成8个总和为0.5的随机数。
我希望从统一分布中随机选择每个数字(即,下面的简单函数不起作用,因为数字不会均匀分布)。
-parameters
代码应该是可推广的,这样你就可以生成N个均匀随机数,它们总和为M(其中M是正浮点数)。如果可能的话,您还可以解释(或用图表显示)为什么您的解决方案在适当的范围内统一生成随机数?
错过商标的相关问题:
Generate multiple random numbers to equal a value in python(当前接受的答案是不均匀的 - 另一个统一的答案只适用于整数)
Getting N random numbers that the sum is M(同样的问题在Java中,目前接受的答案是完全错误的,也没有统一分布的答案)
Generate N random integers that sum to M in R(同样的问题,但在R中,正常 - 不均匀 - 分布)
非常感谢任何帮助。
答案 0 :(得分:4)
你所要求的似乎是不可能的。
但是,我会重新解释您的问题,以便更有意义并且可以解决。您需要的是七维超平面x_1 + x_2 + ... + x_8 = 0.5
上的概率分布。由于超平面的范围是无限的,因此整个超平面上的均匀分布将不起作用。您可能(?)想要的是所有x_i>0
的超平面块。该区域是单形,三角形的一般化,单形上的均匀分布是Dirichlet分布的一个特例。
你可能会发现Dirichlet发布维基百科文章string cutting的这一部分,特别有启发性。
<强>实施强>
维基百科文章在Random Number Generation部分的Python中提供了以下实现:
params = [a1, a2, ..., ak]
sample = [random.gammavariate(a,1) for a in params]
sample = [v/sum(sample) for v in sample]
您可能(?)想要的是所有ai=1
导致单纯形均匀分布的情况。此处k
对应于您问题中的N
个数字。要将样本汇总到M
而不是1
,只需将sample
乘以M
。
<强>更新强>
感谢Severin Pappadeux指出,在极少数情况下,伽玛变量可以返回无穷大。这在数学上是不可能的&#34;但是可以作为浮点数方面的实现工件出现。我处理这种情况的建议是在首次计算sample
之后检查它;如果sample
的任何组件都是无穷大,则将所有非无限分量设置为0并将所有无穷大分量设置为1.然后,当计算xi
时,结果如xi=1, all other x's=0
,或xi=1/2, xj=1/2, all other x's=0
将导致集体&#34;角落样本&#34;和#34;边缘样本&#34;。
另一个非常低概率的可能性是伽马变换的总和溢出。我猜我们可以通过整个底层伪随机数序列而不是看到这种情况发生,但理论上它是可能的(取决于底层的伪随机数发生器)。可以通过重新调整sample
来处理这种情况,例如,在计算了伽马变换之后但在计算x之前,将sample
的所有元素除以N
。就个人而言,我不会因为赔率太低而烦恼;程序崩溃由于其他原因会有更高的概率。
答案 1 :(得分:2)
我们可以从“0-M”范围内的均匀分布中选择“n-1”随机区间,而不是从均匀分布中选择“n”个数,然后我们可以提取区间。 / p>
from random import uniform as rand
def randConstrained(n, M):
splits = [0] + [rand(0, 1) for _ in range(0,n-1)] + [1]
splits.sort()
diffs = [x - splits[i - 1] for i, x in enumerate(splits)][1:]
result = map(lambda x:x*M, diffs)
return result
res = randConstrained(8,0.5)
print res
print sum(res)
输出
[0.0004411388173262698,
0.014832306834761111,
0.009695872790939863,
0.04539251424140245,
0.18791325446494067,
0.07615024971405443,
0.07792489571128014,
0.08764976742529507]
0.5
答案 2 :(得分:0)
对于一个完全通用的解决方案(&#34;我想要n
和low
之间的high
个数字,该总和为m
):
from random import uniform as rand
def randConstrained(n, m, low, high):
tot = m
if not low <= 0 <= high:
raise ValueError("Cannot guarantee a solution when the input does not allow for 0s")
answer = []
for _ in range(n-1):
answer.append(low + rand(0,tot) * (high-low))
tot -= answer[-1]
answer.append(m-sum(answer))
return answer
对于您的情况,可以按如下方式使用:
In [35]: nums = randConstrained(8, 0.5, 0, 1)
In [36]: nums
Out[36]:
[0.2502590281277123,
0.082663797709837,
0.14586995648173873,
0.011270073049224807,
0.009328970756471237,
0.00021993111786291258,
0.0001831479074098452,
0.000205094849743237]
答案 3 :(得分:0)
它被称为单纯形采样,它与Dirichlet分布密切相关。 Sum(x_i)= 1,其中每个x_i是U(0,1)。在你的情况下,在单纯采样之后,只需将每个x_i乘以0.5。
无论如何,将c ++代码从https://github.com/Iwan-Zotow/SimplexSampling转换为python(希望,没有太多错误)
它处理无限正确
"text ..."
答案 4 :(得分:0)
与k4vin的解决方案相同,但没有导入错误,而我是随机的。均匀。
import random
def rand_constrained(n, total):
# l is a sorted list of n-1 random numbers between 0 and total
l = sorted([0] + [total * random.random() for i in range(n - 1)] + [total])
# Return the intervals between each successive element
return [l[i + 1] - l[i] for i in range(n)]
print(rand_constrained(3, 10))
# [0.33022261483938276, 8.646666440311822, 1.0231109448487956]
但是matplotlib在安装时很窒息,所以我现在无法将其绘制出来。