[英]Create a number of random values within a certain range that sums up to 1
我想创建 9 个总和为 1 的随机值。 9 个值中的每一个都必须在存储在数组 s 中的特定范围内
s = np.array([
[0.1 , 0.3 ],
[0.05, 0.2 ],
[0.15, 0.2 ],
[0.15, 0.3 ],
[0.05, 0.15],
[0.07, 0.15],
[0.1 , 0.2 ],
[0.05, 0.15],
[0.01, 0.1 ]])
在数组 s 中,第一列是范围的下限,第二列是上限。 因此,9 的第一个值必须介于 0.1 和 0.3 之间,第二个值介于 0.05 和 0.2 之间,以此类推,所有值的总和为 1。
这是我最近的尝试
def randomtosum(ranges, total):
result = []
for x, y in ranges:
result.append(random.uniform(x,y))
result.append(total - sum(result))
return result
r = randomtosum(s,1)
但这总是会产生第 10 个负值......
有谁知道如何解决这个问题?
一个简短的、hacky 的方法是使用您的“total - sum”值作为最后一个值并检查它是否符合边界,如果不符合,请重试整个列表:
import numpy as np
import random
s = np.array([
[0.1, 0.3],
[0.05, 0.2],
[0.15, 0.2],
[0.15, 0.3],
[0.05, 0.15],
[0.07, 0.15],
[0.1, 0.2],
[0.05, 0.15],
[0.01, 0.1]])
def is_possible(ranges, total) -> bool:
mins = 0
maxs = 0
for x, y in ranges:
mins += x
maxs += y
return mins < total < maxs
def randomtosum(ranges, total) -> list:
if is_possible(ranges, total):
return get_randomtosum(ranges, total)
else:
return []
def get_randomtosum(ranges, total) -> list:
result = []
for x, y in ranges[:-1]:
result.append(random.uniform(x, y))
tmp = total - sum(result)
if ranges[-1][0] < tmp < ranges[-1][1]:
result.append(tmp)
return result
else:
return randomtosum(ranges, total)
r = randomtosum(s, 1)
print(r)
快速而肮脏的解决方案:
import numpy as np
import random
s = np.array([
[0.1 , 0.3 ],
[0.05, 0.2 ],
[0.15, 0.2 ],
[0.15, 0.3 ],
[0.05, 0.15],
[0.07, 0.15],
[0.1 , 0.2 ],
[0.05, 0.15],
[0.01, 0.1 ]])
raw_rands = [random.uniform(x,y) for x,y in s]
while sum(raw_rands) >= 1:
raw_rands = [random.uniform(x,y) for x,y in s]
如果 while 循环运行直到满足条件的想法让您感到害怕,也让我感到害怕,您可以尝试使用限制迭代次数的范围。
raw_rands = [random.uniform(x,y) for x,y in s]
for i in range(1000):
if sum(raw_rands) <= 1:
break
new_raw_rands = [random.uniform(x,y) for x,y in s]
if sum(new_raw_rands) < sum(raw_rands):
raw_rands = [random.uniform(x,y) for x,y in s]
如果它没有得到至少小于或等于 1 的随机变量总和,它将获得具有最小总和值的迭代。
使用各个范围对随机数进行加权。 归一化为 1——低点的总和。 添加到低点。
import numpy as np
s = np.array([
[0.1 , 0.3 ],
[0.05, 0.2 ],
[0.15, 0.2 ],
[0.15, 0.3 ],
[0.05, 0.15],
[0.07, 0.15],
[0.1 , 0.2 ],
[0.05, 0.15],
[0.01, 0.1 ]])
low = s[ :, 0] # Array of low limits
rng = s[ :, 1] - low # Array of the range of each row
free = 1.0 - low.sum() # the free value in play 1 - sum lo
np.random.seed( 1234 ) # Make reproducable, remove in real version.
rnd = np.random.random( size = len(rng)) * rng # random weighted by the ranges
rnd = rnd * free / rnd.sum() # Normalise to free
result = low + rnd
print( result, 'Sum ', result.sum() )
# [0.11829863 0.09457931 0.16045562 0.20627753 0.08726121
# 0.08041789 0.11320732 0.08830725 0.05119523] Sum 1.0
把它变成一个函数。
def sum_to_one( s ):
low = s[ :, 0] # Array of low limits
rng = s[ :, 1] - low # Array of the range of each row
free = 1.0 - low.sum() # the free value in play 1 - sum lo
rnd = np.random.random( size = len(rng)) * rng # random weighted by the ranges
rnd = rnd * free / rnd.sum() # Normalise to free
return low + rnd
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.