Python - 如何创建一个浮动列表,当它们的大小在特定范围内随机化并且它们的总和是预先确定的
Python - How to create a list of floats when their sizes randomized within a specific range and their sum is predetermined
正如标题中所写,我对一种生成长度为 'N 的浮点数列表的简单方法很感兴趣,其值范围从 0.1 到 0.25 但其总和将是固定的和预定义的
例子一:
N = 9,总和 = 1.575,列表 = (0.11, 0.24, 0.225, 0.16, 0.169, 0.233, 0.102, 0.2, 0.136)
示例 B:
N = 2,总和 = 0.35,列表 = (0.2, 0.15)
谢谢!
尝试这将提供从 0.1 到 0.25 的值范围列表,其长度为 N,总和如提供的那样
import random
def num_pieces(num):
resp_list = []
while True:
rnd_num = random.uniform(0.1, 0.25)
resp_list.append(rnd_num)
if sum(resp_list) >= num:
break
return resp_list
a = num_pieces(.9)
如果你想限制范围使用这个
round(random.uniform(1,2), N)
已更新
import random
def num_pieces(num):
deci_points = len(str(num).split('.')[1])
resp_list = []
while True:
rnd_num = round(random.uniform(0.1, 0.25),deci_points)
resp_list.append(rnd_num)
if sum(resp_list) >= num:
break
return resp_list
人们很想使用 Dirichlet distribution,其中 return 是 rank 小于 1 的正实数的向量,其和被限制为等于 1.
但是,有一个问题:即使是线性尺度的狄利克雷分布{xi} --> {a*xi + b} 只有 2 个自由参数。我们的问题有 3:xMin = 0.1、xMax = 0.25、xSum = 1.575,以从您的第一个示例中获取值。所以我们没有明显的方法来直接实现 xi <= xMax 约束。
9 阶的合法单位 Dirichlet 变量可以由一个 1.0 值后跟 8 个零值组成。合法缩放的 Dirichlet 变量可以由单个值 0.775 和后面的 8 个值 0.1 组成,给出所需的总和值。所以我们有一种“赢家通吃”的可能性。
但是我们总是可以通过直接拒绝来实现 xMax 约束。根据确切的参数,拒绝的代价可能会很高,但至少我们的统计基础是可靠的。
我们只是计算缩放狄利克雷变量,直到我们得到一个符合 xi <= xMax 约束的变量。我们 return 那个给来电者。
这可以通过以下Python代码实现:
import numpy as np
import numpy.random as nprd
def getRandList(rng, rank, xMin, xMax, xSum):
delta = xSum - rank*xMin
allowedMaxShare = (xMax-xMin) / delta
#### print("allowedMaxShare = %f" % allowedMaxShare)
alphas = rank * [1.0] # uniform list
rejectionCount = 0
maxShare = 2.0 # certainly above allowedMaxShare
while (maxShare > allowedMaxShare):
rejectionCount += 1
v1 = rng.dirichlet(alphas)
maxShare = max(v1)
#### print("rejectionCount = %d" % rejectionCount)
# scale the successful vector:
v2 = list (map(lambda r: xMin + r*delta, v1))
return v2
试用运行:
$ python3
Python 3.9.6 (default, Jul 16 2021, 00:00:00)
>>>
>>> import numpy as np
>>> import numpy.random as nprd
>>> from soq import getRandList
>>>
>>> rank=9
>>> xMin=0.1
>>> xMax=0.25
>>> xSum=1.575
>>> randomSeed=42
>>> g0 = nprd.default_rng(randomSeed)
>>>
>>> v = getRandList(rg0, rank, xMin, xMax, xSum)
>>>
>>> v
[0.14802819801539244, 0.12496501874018585, 0.19078664992587546, 0.18722819613343228, 0.22566529897386292, 0.14102174372855228, 0.20502851332070077, 0.24961569590423102, 0.10266068525776693]
>>>
>>> sum(v)
1.575
>>>
>>> min(v)
0.10266068525776693
>>>
>>> max(v)
0.24961569590423102
>>>
看起来不错。让我们再测试一下:
for _ in range(5):
v = getRandList(rg0, rank, xMin, xMax, xSum)
#### print("v = %s" % v)
sv = sum(v) ; mx = max(v) ; mn = min(v)
print("sum = %f min=%f max=%f" % (sv, mn, mx))
测试脚本输出:
sum = 1.575000 min=0.115170 max=0.248764
sum = 1.575000 min=0.113341 max=0.239323
sum = 1.575000 min=0.100097 max=0.228379
sum = 1.575000 min=0.101264 max=0.246103
sum = 1.575000 min=0.107969 max=0.238713
所以看起来基本正确。通过拥有一个专用的生成器对象,代码仍然可以进行一些优化,同时保留拒绝原则。该对象可以缓冲大量矢量尺度 Dirichlet 变量,并将原始生成器与计算常量(例如 allowedMaxShare
.
一起托管
正如标题中所写,我对一种生成长度为 'N 的浮点数列表的简单方法很感兴趣,其值范围从 0.1 到 0.25 但其总和将是固定的和预定义的
例子一:
N = 9,总和 = 1.575,列表 = (0.11, 0.24, 0.225, 0.16, 0.169, 0.233, 0.102, 0.2, 0.136)
示例 B:
N = 2,总和 = 0.35,列表 = (0.2, 0.15)
谢谢!
尝试这将提供从 0.1 到 0.25 的值范围列表,其长度为 N,总和如提供的那样
import random
def num_pieces(num):
resp_list = []
while True:
rnd_num = random.uniform(0.1, 0.25)
resp_list.append(rnd_num)
if sum(resp_list) >= num:
break
return resp_list
a = num_pieces(.9)
如果你想限制范围使用这个
round(random.uniform(1,2), N)
已更新
import random
def num_pieces(num):
deci_points = len(str(num).split('.')[1])
resp_list = []
while True:
rnd_num = round(random.uniform(0.1, 0.25),deci_points)
resp_list.append(rnd_num)
if sum(resp_list) >= num:
break
return resp_list
人们很想使用 Dirichlet distribution,其中 return 是 rank 小于 1 的正实数的向量,其和被限制为等于 1.
但是,有一个问题:即使是线性尺度的狄利克雷分布{xi} --> {a*xi + b} 只有 2 个自由参数。我们的问题有 3:xMin = 0.1、xMax = 0.25、xSum = 1.575,以从您的第一个示例中获取值。所以我们没有明显的方法来直接实现 xi <= xMax 约束。
9 阶的合法单位 Dirichlet 变量可以由一个 1.0 值后跟 8 个零值组成。合法缩放的 Dirichlet 变量可以由单个值 0.775 和后面的 8 个值 0.1 组成,给出所需的总和值。所以我们有一种“赢家通吃”的可能性。
但是我们总是可以通过直接拒绝来实现 xMax 约束。根据确切的参数,拒绝的代价可能会很高,但至少我们的统计基础是可靠的。
我们只是计算缩放狄利克雷变量,直到我们得到一个符合 xi <= xMax 约束的变量。我们 return 那个给来电者。
这可以通过以下Python代码实现:
import numpy as np
import numpy.random as nprd
def getRandList(rng, rank, xMin, xMax, xSum):
delta = xSum - rank*xMin
allowedMaxShare = (xMax-xMin) / delta
#### print("allowedMaxShare = %f" % allowedMaxShare)
alphas = rank * [1.0] # uniform list
rejectionCount = 0
maxShare = 2.0 # certainly above allowedMaxShare
while (maxShare > allowedMaxShare):
rejectionCount += 1
v1 = rng.dirichlet(alphas)
maxShare = max(v1)
#### print("rejectionCount = %d" % rejectionCount)
# scale the successful vector:
v2 = list (map(lambda r: xMin + r*delta, v1))
return v2
试用运行:
$ python3
Python 3.9.6 (default, Jul 16 2021, 00:00:00)
>>>
>>> import numpy as np
>>> import numpy.random as nprd
>>> from soq import getRandList
>>>
>>> rank=9
>>> xMin=0.1
>>> xMax=0.25
>>> xSum=1.575
>>> randomSeed=42
>>> g0 = nprd.default_rng(randomSeed)
>>>
>>> v = getRandList(rg0, rank, xMin, xMax, xSum)
>>>
>>> v
[0.14802819801539244, 0.12496501874018585, 0.19078664992587546, 0.18722819613343228, 0.22566529897386292, 0.14102174372855228, 0.20502851332070077, 0.24961569590423102, 0.10266068525776693]
>>>
>>> sum(v)
1.575
>>>
>>> min(v)
0.10266068525776693
>>>
>>> max(v)
0.24961569590423102
>>>
看起来不错。让我们再测试一下:
for _ in range(5):
v = getRandList(rg0, rank, xMin, xMax, xSum)
#### print("v = %s" % v)
sv = sum(v) ; mx = max(v) ; mn = min(v)
print("sum = %f min=%f max=%f" % (sv, mn, mx))
测试脚本输出:
sum = 1.575000 min=0.115170 max=0.248764
sum = 1.575000 min=0.113341 max=0.239323
sum = 1.575000 min=0.100097 max=0.228379
sum = 1.575000 min=0.101264 max=0.246103
sum = 1.575000 min=0.107969 max=0.238713
所以看起来基本正确。通过拥有一个专用的生成器对象,代码仍然可以进行一些优化,同时保留拒绝原则。该对象可以缓冲大量矢量尺度 Dirichlet 变量,并将原始生成器与计算常量(例如 allowedMaxShare
.