繁体   English   中英

在一定范围内创建多个随机值,总和为 1

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM