生成多个随机数以等于python中的值

Jac*_* S. 32 python random

所以这是交易:我想(例如)生成4个伪随机数,当加在一起时将等于40.这怎么可能在python中圆顶?我可以生成一个随机数1-40,然后在1和剩余部分之间生成另一​​个数字等,但是第一个数字将更有可能"抓住"更多.

Mar*_*son 83

这是标准解决方案.这与Laurence Gonsalves的答案相似,但与答案相比有两个优点.

  1. 它是统一的:每个组合的4个正整数加起来40,同样可能会提出这个方案.

  1. 它很容易适应其他总数(7个数字加起来等等)
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)

  • 如果你需要约束生成的整数高于某个值``low``,这可以通过用``a - b +(low-1)``替换``a - b``来实现通过将``total``的两个实例替换为``total - (min-1)*n``来补偿新总和中的`n*(low-1)``增加.我还没有找到一种方法来添加一个"高"阈值. (3认同)

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",但这可以很容易地为浮点数推广.)

以下是它的工作原理:

  • 随机减少两个总范围,即b.奇数范围是因为中点以下至少有2个,而且至少有2个以上.(这来自每个值的最小值1).
  • 随机地将每个范围切成两个.同样,界限是最小的1.
  • 返回每个切片的大小.他们将加起来40.

  • 我认为你需要`a = random.randint(1,b-1)`和`c = random.randint(b + 1,39)`以确保你没有在输出列表中得到零.此外,这有一个稍微独特的分布:形式为"[1,1,x,38-x]"的结果比均匀分布的结果更可能发生. (3认同)

lal*_*lli 8

生成4个随机数,计算它们的总和,将每个数除以总和并乘以40.

如果你想要整数,那么这将需要一点非随机性.


Rug*_*rra 6

使用多项式分布

from numpy.random import multinomial
multinomial(40, [1/4.] * 4)
Run Code Online (Sandbox Code Playgroud)

  • 显然是最干净和最坚固的解决方案,但可能在答案中多一些解释会帮助OP理解_为什么_这是最好的答案 (2认同)