[英]How to generate a list of random numbers so their sum would be equal to a randomly chosen number
I want to generate a list of random distribution of numbers so their sum would be equal to a randomly chosen number.我想生成一个随机分布的数字列表,以便它们的总和等于随机选择的数字。 For example, if randomly chosen number is 5, the distribution would be [1 2 2] or [2 3] or [1 1 1 2] and so on.
例如,如果随机选择的数字是 5,则分布将是 [1 2 2] 或 [2 3] 或 [1 1 1 2] 等等。 Any suggestions are welcome!
欢迎任何建议!
Let n
be the number you want values to add up to.让
n
是您希望值相加的数字。 Generate a random sample
of random size (less than n
), consisting of values in the range 1 to n
exclusive of n
.生成随机大小(小于
n
)的随机sample
,由 1 到n
范围内的值组成,不包括n
。 Now add the endpoints 0 and n
, and sort.现在添加端点 0 和
n
,然后排序。 Successive differences of the sorted values will sum to n
.排序值的连续差值的总和为
n
。
import random as r
def random_sum_to(n):
a = r.sample(range(1, n), r.randint(1, n-1)) + [0, n]
list.sort(a)
return [a[i+1] - a[i] for i in range(len(a) - 1)]
print(random_sum_to(20)) # yields, e.g., [4, 1, 1, 2, 4, 2, 2, 4]
If you'd like to be able to specify the number of terms in the sum explicitly, or have it be random if unspecified, add an optional argument:如果您希望能够明确指定总和中的项数,或者如果未指定则使其是随机的,请添加一个可选参数:
import random as r
def random_sum_to(n, num_terms = None):
num_terms = (num_terms or r.randint(2, n)) - 1
a = r.sample(range(1, n), num_terms) + [0, n]
list.sort(a)
return [a[i+1] - a[i] for i in range(len(a) - 1)]
print(random_sum_to(20, 3)) # [9, 7, 4] for example
print(random_sum_to(5)) # [1, 1, 2, 1] for example
In a loop, you could keep drawing a random number between 1 and the remaining sum until you've reached your total在循环中,您可以继续在 1 和剩余总和之间绘制一个随机数,直到达到总数
from random import randint
def generate_values(n):
values = []
while n > 0:
value = randint(1, n)
values.append(value)
n -= value
return values
A few samples of such a function此类函数的一些示例
>>> generate_values(20)
[17, 1, 1, 1]
>>> generate_values(20)
[10, 4, 4, 1, 1]
>>> generate_values(20)
[14, 4, 1, 1]
>>> generate_values(20)
[5, 2, 4, 1, 5, 1, 1, 1]
>>> generate_values(20)
[2, 13, 5]
>>> generate_values(20)
[14, 3, 2, 1]
Consider doing it continuously first.考虑先连续做。 And for a moment we do not care about final number, so let's sample uniformly X_i in the interval [0...1] so that their sum is equal to 1
暂时我们不关心最终数字,所以让我们在区间 [0...1] 中均匀采样 X_i,使它们的总和等于 1
X_1 + X_2 + ... X_n = 1
This is well-known distribution called Dirichlet Distribution, or gamma variate, or simplex sampling.这是众所周知的分布,称为狄利克雷分布,或伽马变量,或单纯形采样。 See details and discussion at Generating N uniform random numbers that sum to M .
请参阅生成总和为 M 的 N 个统一随机数的详细信息和讨论。 One can use
random.gammavariate(a,1)
or for correct handling of corners gamma variate with parameter 1 is equivalent exponential distribution, with direct sampling code below可以使用
random.gammavariate(a,1)
或正确处理角点 gamma 变量,参数为 1 是等效指数分布,直接采样代码如下
def simplex_sampling(n):
r = []
sum = 0.0
for k in range(0,n):
x = random.random()
if x == 0.0:
return (1.0, make_corner_sample(n, k))
t = -math.log(x)
r.append(t)
sum += t
return (sum, r)
def make_corner_sample(n, k):
r = []
for i in range(0, n):
if i == k:
r.append(1.0)
else:
r.append(0.0)
return r
So from simplex_sampling
you have vector and the sum to be used as normalization.所以从
simplex_sampling
你有向量和要用作归一化的总和。
Thus, to use it for, say, N=5因此,将其用于,例如,N=5
N = 5
sum, r = simplex_sampling(N)
norm = float(N)/sum
# normalization together with matching back to integers
result = []
for k in range(N):
# t is now float uniformly distributed in [0.0...N], with sum equal to N
t = r[k] * norm
# not sure if you could have zeros,
# and check for boundaries might be useful, but
# conversion to integers is trivial anyway:
# values in [0...1) shall be converted to 0,
# values in [1...2) shall be converted to 1, etc
result.append( int(t) )
here's a simple way to have, a random list of probabilities, where there sum is equal to one;这是一个简单的方法,一个随机的概率列表,其中总和等于 1;
a = np.random.random(2)
a /=sum(a)
a
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.