生成随机浮点数,求和为 1,具有最小值
Generating random floats, summing to 1, with minimum value
我看到了很多在特定范围内生成随机浮点数的解决方案(比如 ) which actually helps me, and solutions for generating random floats summing to 1 (like this),并且单独的解决方案工作得很好,但我不知道如何合并它们。
目前我的代码是:
import random
def sample_floats(low, high, k=1):
""" Return a k-length list of unique random floats
in the range of low <= x <= high
"""
result = []
seen = set()
for i in range(k):
x = random.uniform(low, high)
while x in seen:
x = random.uniform(low, high)
seen.add(x)
result.append(x)
return result
还在申请中
weights = sample_floats(0.055, 1.0, 11)
weights /= np.sum(weights)
Returns weights
数组,其中有一些浮点数少于0.055
我应该在上面的函数中以某种方式实现np.random.dirichlet
,还是应该在np.random.dirichlet
的基础上构建,然后实现条件> 0.055
?想不出任何解决方案。
谢谢指教!
样本是相关的,所以我相信你不能以 IID 方式生成它们。但是,您可以以迭代方式进行。例如,您可以按照我在下面的代码中显示的那样进行操作。还有一些特殊情况需要检查,比如如果用户输入 low
import random
import warnings
def sample_floats(low = 0.055, high = 1., x_sum = 1., k = 1):
""" Return a k-length list of unique random floats
in the range of 'low' <= x <= 'high' summing up to 'sum'.
"""
sum_i = 0
xs = []
if x_sum - (k-1)*low < high:
warnings.warn(f'high = {high} is to high to be generated under the'
f' conditions set by k = {k}, sum = {x_sum}, and low = {low}.'
f' high automatically set to {x_sum - (k-1)*low}.')
if k == 1:
if high < x_sum:
raise ValueError(f'The parameter combination k = {k}, sum = {x_sum},'
' and high = {high} is impossible.')
else: return x_sum
high_i = high
for i in range(k-1):
x = random.uniform(low, high_i)
xs.append(x)
sum_i = sum_i + x
if high < (x_sum - sum_i - (k-1-i)*low):
high_i = high
else: high_i = x_sum - sum_i - (k-1-i)*low
xs.append(x_sum - sum_i)
return xs
例如:
random.seed(0)
xs = sample_floats(low = 0.055, high = 0.5, x_sum = 1., k = 5)
print(xs)
print(sum(xs))
输出:
[0.43076772392864643, 0.27801464913542906, 0.08495210994346317, 0.06568433355884717, 0.14058118343361425]
1.0
您可以通过改变统一随机数生成器的下限和上限来迭代生成 k-1
数字 - 任何迭代的约束是生成的数字允许其余数字至少为 low
def sample_floats(low, high, k=1):
result = []
generated = 0
while generated < k-1:
current_higher_bound = max(low, 1 - (k - 1 - generated)*low - sum(result))
next_num = random.uniform(low, current_higher_bound)
result.append(next_num)
generated += 1
last_num = 1 - sum(result)
result.append(last_num)
return result
print(sample_floats(0.01, 1, k=15))
#[0.08878760926151083,
# 0.17897435239586243,
# 0.5873150041878156,
# 0.021487776792166513,
# 0.011234379498998357,
# 0.012408564286727042,
# 0.015391011259745103,
# 0.01264921242128719,
# 0.010759267284382326,
# 0.010615007333002748,
# 0.010288605412288477,
# 0.010060487014659121,
# 0.010027216923973544,
# 0.010000064276203318,
# 0.010001441651377285]
IIUC,您想生成一个 k
值的数组,最小值为 low=0.055
.
更容易从 0 生成总和为 1-low*k
的数字,然后添加 low
以便最终数组总和为 1。因此,这保证了下限和总和。
关于 high
,我很确定添加此约束在数学上是不可能的,因为一旦您确定了下限和总和,就没有足够的自由度来选择上限。上限将为 1-low*(k-1)
(此处为 0.505)。
此外,请注意,对于最小值,您必须强制执行最大值 k
的 1//low
(此处为 18 个值)。如果您将 k
设置得更高,则下限将不正确。
# parameters
low = 0.055
k = 10
a = np.random.rand(k)
a = (a/a.sum()*(1-low*k))
weights = a+low
# checking that the sum is 1
assert np.isclose(weights.sum(), 1)
示例输出:
array([0.13608635, 0.06796974, 0.07444545, 0.1361171 , 0.07217206,
0.09223554, 0.12713463, 0.11012871, 0.1107402 , 0.07297022])
我看到了很多在特定范围内生成随机浮点数的解决方案(比如
目前我的代码是:
import random
def sample_floats(low, high, k=1):
""" Return a k-length list of unique random floats
in the range of low <= x <= high
"""
result = []
seen = set()
for i in range(k):
x = random.uniform(low, high)
while x in seen:
x = random.uniform(low, high)
seen.add(x)
result.append(x)
return result
还在申请中
weights = sample_floats(0.055, 1.0, 11)
weights /= np.sum(weights)
Returns weights
数组,其中有一些浮点数少于0.055
我应该在上面的函数中以某种方式实现np.random.dirichlet
,还是应该在np.random.dirichlet
的基础上构建,然后实现条件> 0.055
?想不出任何解决方案。
谢谢指教!
样本是相关的,所以我相信你不能以 IID 方式生成它们。但是,您可以以迭代方式进行。例如,您可以按照我在下面的代码中显示的那样进行操作。还有一些特殊情况需要检查,比如如果用户输入 low 例如: 输出:import random
import warnings
def sample_floats(low = 0.055, high = 1., x_sum = 1., k = 1):
""" Return a k-length list of unique random floats
in the range of 'low' <= x <= 'high' summing up to 'sum'.
"""
sum_i = 0
xs = []
if x_sum - (k-1)*low < high:
warnings.warn(f'high = {high} is to high to be generated under the'
f' conditions set by k = {k}, sum = {x_sum}, and low = {low}.'
f' high automatically set to {x_sum - (k-1)*low}.')
if k == 1:
if high < x_sum:
raise ValueError(f'The parameter combination k = {k}, sum = {x_sum},'
' and high = {high} is impossible.')
else: return x_sum
high_i = high
for i in range(k-1):
x = random.uniform(low, high_i)
xs.append(x)
sum_i = sum_i + x
if high < (x_sum - sum_i - (k-1-i)*low):
high_i = high
else: high_i = x_sum - sum_i - (k-1-i)*low
xs.append(x_sum - sum_i)
return xs
random.seed(0)
xs = sample_floats(low = 0.055, high = 0.5, x_sum = 1., k = 5)
print(xs)
print(sum(xs))
[0.43076772392864643, 0.27801464913542906, 0.08495210994346317, 0.06568433355884717, 0.14058118343361425]
1.0
您可以通过改变统一随机数生成器的下限和上限来迭代生成 k-1
数字 - 任何迭代的约束是生成的数字允许其余数字至少为 low
def sample_floats(low, high, k=1):
result = []
generated = 0
while generated < k-1:
current_higher_bound = max(low, 1 - (k - 1 - generated)*low - sum(result))
next_num = random.uniform(low, current_higher_bound)
result.append(next_num)
generated += 1
last_num = 1 - sum(result)
result.append(last_num)
return result
print(sample_floats(0.01, 1, k=15))
#[0.08878760926151083,
# 0.17897435239586243,
# 0.5873150041878156,
# 0.021487776792166513,
# 0.011234379498998357,
# 0.012408564286727042,
# 0.015391011259745103,
# 0.01264921242128719,
# 0.010759267284382326,
# 0.010615007333002748,
# 0.010288605412288477,
# 0.010060487014659121,
# 0.010027216923973544,
# 0.010000064276203318,
# 0.010001441651377285]
IIUC,您想生成一个 k
值的数组,最小值为 low=0.055
.
更容易从 0 生成总和为 1-low*k
的数字,然后添加 low
以便最终数组总和为 1。因此,这保证了下限和总和。
关于 high
,我很确定添加此约束在数学上是不可能的,因为一旦您确定了下限和总和,就没有足够的自由度来选择上限。上限将为 1-low*(k-1)
(此处为 0.505)。
此外,请注意,对于最小值,您必须强制执行最大值 k
的 1//low
(此处为 18 个值)。如果您将 k
设置得更高,则下限将不正确。
# parameters
low = 0.055
k = 10
a = np.random.rand(k)
a = (a/a.sum()*(1-low*k))
weights = a+low
# checking that the sum is 1
assert np.isclose(weights.sum(), 1)
示例输出:
array([0.13608635, 0.06796974, 0.07444545, 0.1361171 , 0.07217206,
0.09223554, 0.12713463, 0.11012871, 0.1107402 , 0.07297022])