【问题标题】:How to generate in python a random number in a range but biased toward some specific numbers?如何在python中生成一个范围内的随机数,但偏向于某些特定数字?
【发布时间】:2021-05-04 06:57:29
【问题描述】:

我想选择一个范围,例如,60 到 80,并从中生成一个随机数。但是,在 65-72 之间我想要一个更高的概率,而除了这个 (60-64 和 73 到 80)之外的其他范围有更低的

一个例子:

来自60-6473-80 也有 35% 的机会被选中。来自65-72 65% 的机会。

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

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

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

在此先感谢愿意贡献的人!

【问题讨论】:

  • 你好,什么是更高的概率?你有它的一些规格还是正常分布好吗?如果是后者,只需使用 numpy 或 scipy 从正态分布中采样。
  • 解决你的问题了吗stackoverflow.com/questions/4265988/…
  • 你的描述很模糊,这让我觉得你不知道你到底想要什么。当规范不明确时,一种流行的仿真建模选择是triangular distribution。使用numpy.org/doc/stable/reference/random/generated/…生成。
  • @EmersonOliveira -- 你想要一个“讲台”形分布,其中区间 [60,64] 中的值和区间 [73,80] 中的值应该是平坦的 pdf=0.175,并且区间 [65,72] 中的值应该是平坦的 pdf=0.65?或者,您想要具有这些额外约束的正态分布吗?
  • 这是一个粗略的方法,你 a = numpy.array([0.65]*16 + [0.35]*5) a = a/sum(a) numpy.random.choice(numpy.arange(60, 81), p=a) 其中60-75 为 65% 的概率,其余 35% 考虑到所有在该 renage 同样可能@EmersonOliveira

标签: python numpy random scipy probability


【解决方案1】:

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

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 &lt;= THRESHOLD[0]) 您将从范围 [65, 72] 中生成。如果做不到这一点,剩下的 13 个可能性中有 5 个(35% 的 5/13)在 [60, 64] 范围内,其余的在 [73, 80] 范围内。 Uniform(0,1) 值u 将有 65% 的时间低于第一个阈值,如果失败,则有 5/13 的时间低于第二个阈值,其余 8/13 的时间高于该阈值。

结果如下所示:

【讨论】:

  • 不错!基本上就是我要找的,谢谢!你能解释一下为什么0.65 + 0.35 * 5 / 13吗?不明白那部分
  • 处理完65-72范围内的主要65%后,剩下0.35个概率。对于这些概率,有两个范围:60–64(5 个数字)和 73–80(8 个数字)。第一个范围共享 0.35 * 5 / (8 + 5) 概率
【解决方案2】:

这是一个基于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 # 表示 1000 个结果值中有 649 个在中间范围 [65,72]

【讨论】:

  • 感谢您分享该解决方案!甚至不需要 count var,因为我只寻找一个输出,因此大小可以固定为 1,但如果最终我需要对更多输出应用相同的计算,那就太好了。谢谢!
  • 如果可能的话,你能评论一下rng*变量所涉及的行吗?我想我没有完全理解它
猜你喜欢
  • 2015-06-02
  • 2011-09-20
  • 1970-01-01
  • 2021-03-02
  • 2013-10-27
  • 2016-05-04
相关资源
最近更新 更多