生成随机浮点数,求和为 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)。

此外,请注意,对于最小值,您必须强制执行最大值 k1//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])