如何在 python 中生成一个范围内但偏向于某些特定数字的随机数?

How to generate in python a random number in a range but biased toward some specific numbers?

我想选择一个范围,例如,60 到 80,然后从中生成一个随机数。但是,介于 65-72 我想要 更高的概率 ,而除此之外的其他范围 (60-64和 73 到 80) 具有较低的.

一个例子:

60-64 开始,73-80 也有 35% 的机会被选中。来自 65-72 65% 的几率。

子范围内的元素出现的可能性相同。我正在生成整数。

另外,一个可扩展的解决方案会很有趣,这样人们就可以将它的使用扩展到更高的范围,例如 1000-2000,但偏向于 1400-1600。

有没有人可以提供一些想法?

预先感谢任何愿意贡献的人!

对于子范围内同样可能的结果,以下方法可以解决问题:

import random

THRESHOLD = [0.65, 0.65 + 0.35 * 5 / 13]

def my_distribution():
    u = random.random()
    if u <= THRESHOLD[0]:
        return random.randint(65, 72)
    elif u <= THRESHOLD[1]:
        return random.randint(60, 64)
    else:
        return random.randint(73, 80)

这使用统一的随机数来确定您所在的子范围,然后生成该子范围内的可能性相同的值。

THRESHOLD 值类似于累积分布函数,但排列方式是首先检查最有可能的结果。 65% 的时间 (u <= THRESHOLD[0]) 您将从 [65, 72] 范围内生成。否则,剩下的 13 种可能性中有 5 种(35% 的 5/13)在 [60, 64] 范围内,其余在 [73, 80] 范围内。 Uniform(0,1) 值 u 将有 65% 的时间低于第一个阈值,否则,有 5/13 的时间低于第二个阈值,其余 8/13 的时间高于该阈值时间.

结果如下所示:

这是一个基于 numpy 的解决方案:

import numpy as np

# Some params
left_start   = 60 # Start of left interval====== [60,64]
middle_start = 65 # Start of middle interval === [65,72]
right_start  = 73 # Start of right interval ===- [73,80]
right_end    = 80 # End of the right interval == [73,80]
count        = 1000 # Number of values to generate.
middle_wt    = 0.65 # Middle range to be selected with wt/prob=0.65

middle       = np.arange(middle_start, right_start)
rest         = np.r_[left_start:middle_start, right_start:(right_end+1)]
rng1 = np.random.default_rng(None) # Generator for randomly choosing range.
rng2 = np.random.default_rng(None) # Generator for generating values in the ranges.
# Now generate a random list of 0s and 1s to indicate choice between
# 'middle' and 'rest'. For this number generation we will set middle_wt as
# the weight/probability for 0 and (1-middle_wt) as the weight/probability for 1.
# (0 indicates middle range and 1 indicates the rest.)
range_choices   = rng1.choice([0,1], replace=True, size=count, p=[middle_wt, (1-middle_wt)])
# Now generate 'count' values for the middle range
middle_choices  = rng2.choice(middle, replace=True, size=count)
# Now generate 'count' values for the 'rest' of the range (non-middle)
rest_choices    = rng2.choice(rest, replace=True, size=count)

result          = np.choose(range_choices, (middle_choices,rest_choices))
print (np.sum((65 <= result) & (result<=72)))

注: 在上面的代码中,p=[middle_wt, (1-middle_wt)] 是一个权重列表。 middle_wt 是中间范围的权重 [65,72](1-middle_wt) 是其余范围的权重。

输出:

649 # Indicates that 649 out of the 1000 values of result are in the middle range [65,72]