所以这是交易:我想(例如)生成4个伪随机数,当加在一起时将等于40.这怎么可能在python中圆顶?我可以生成一个随机数1-40,然后在1和剩余部分之间生成另一个数字等,但是第一个数字将更有可能"抓住"更多.
Mar*_*son 83
这是标准解决方案.这与Laurence Gonsalves的答案相似,但与答案相比有两个优点.
和
import random
def constrained_sum_sample_pos(n, total):
"""Return a randomly chosen list of n positive integers summing to total.
Each such list is equally likely to occur."""
dividers = sorted(random.sample(range(1, total), n - 1))
return [a - b for a, b in zip(dividers + [total], [0] + dividers)]
Run Code Online (Sandbox Code Playgroud)
样本输出:
>>> constrained_sum_sample_pos(4, 40)
[4, 4, 25, 7]
>>> constrained_sum_sample_pos(4, 40)
[9, 6, 5, 20]
>>> constrained_sum_sample_pos(4, 40)
[11, 2, 15, 12]
>>> constrained_sum_sample_pos(4, 40)
[24, 8, 3, 5]
Run Code Online (Sandbox Code Playgroud)
说明:有之间的一对一的对应(1)4元组(a, b, c, d)
的正整数,使得a + b + c + d == 40
,和(2)的整数三元组(e, f, g)
用0 < e < f < g < 40
,并且可以很容易地产生,后者使用random.sample
.对应关系由(e, f, g) = (a, a + b, a + b + c)
一个方向和(a, b, c, d) = (e, f - e, g - f, 40 - g)
反方向给出.
如果你想要非负整数(即允许0
)而不是正整数,那么就有一个简单的变换:如果(a, b, c, d)
非负整数求和40
那么求积分(a+1, b+1, c+1, d+1)
的正整数44
,反之亦然.使用这个想法,我们有:
def constrained_sum_sample_nonneg(n, total):
"""Return a randomly chosen list of n nonnegative integers summing to total.
Each such list is equally likely to occur."""
return [x - 1 for x in constrained_sum_sample_pos(n, total + n)]
Run Code Online (Sandbox Code Playgroud)
图形说明constrained_sum_sample_pos(4, 10)
,感谢@FM.(稍微编辑.)
0 1 2 3 4 5 6 7 8 9 10 # The universe.
| | # Place fixed dividers at 0, 10.
| | | | | # Add 4 - 1 randomly chosen dividers in [1, 9]
a b c d # Compute the 4 differences: 2 3 4 1
Run Code Online (Sandbox Code Playgroud)
Lau*_*ves 12
b = random.randint(2, 38)
a = random.randint(1, b - 1)
c = random.randint(b + 1, 39)
return [a, b - a, c - b, 40 - c]
Run Code Online (Sandbox Code Playgroud)
(我假设你想要整数,因为你说"1-40",但这可以很容易地为浮点数推广.)
以下是它的工作原理:
使用多项式分布
from numpy.random import multinomial
multinomial(40, [1/4.] * 4)
Run Code Online (Sandbox Code Playgroud)