【问题标题】:A weighted version of random.randintrandom.randint 的加权版本
【发布时间】:2020-07-07 06:02:45
【问题描述】:

我想在ab(都包括在内)之间选择一个随机整数,统计权重为c

c 是一个介于ab 之间的值。

将权重因子c 应用于random.randint 的最有效方法是什么?

我得到的最接近的是this问题,但有很大的不同:

我只有一个统计权重c,而不是ab 之间的每个值的统计概率。

例子:

a = 890
b = 3200

c = 2600

print(random.randint(a,b))

>>>> supposed to result most frequently in a value around 2600

我并不真正关心ab 之间的分布,只要c 上有权重即可。但是,高斯分布会很受欢迎。

请注意:此问题解决numpy.random 模块的问题,如this 问题。

【问题讨论】:

  • 问题是 supposed to most often result in a value around 2600 不够具体:我们可以调整均匀分布或高斯分布,对于后者,我们可以使用大或小的标准差。你到底想要什么?
  • 听起来他们想要c 作为模式。
  • @SergeBallesta:我进行了编辑,在新段落中提到了分布类型。

标签: python random weighted


【解决方案1】:

听起来triangular distribution 可能符合您的需求。 ab 的值分别是 minmaxc 对应于 mode(最有可能的结果) 的分布。

numpy.random 中有一个三角生成器。它会生成浮点数,但您可以对结果进行四舍五入然后整数化。如果您很挑剔,这将稍微偏离最小值和最大值,与其他整数值相比,它们只有一半的范围,因此预期计数的一半。统计学家使用连续性校正来调整从实数到整数的范围转换:从最小值中减去 1/2,在最大值上加上 1/2。如果您正在处理小范围,这很可能是相关的,如下面的小示例所示。

import numpy as np
import matplotlib.pyplot as plt

# replace with your actual values
a = 1
b = 5
c = 2

# Without continuity correction
plt.hist(np.ma.round(np.random.triangular(
          left = a,
          mode = c,
          right = b, 
          size = 100000)
        ).astype(int),
        range = (0.5, 5.5), bins = 50, density = True)
plt.show()

# With continuity correction
plt.hist(np.ma.round(np.random.triangular(
          left = a - 0.5,
          mode = c,
          right = b + 0.5, 
          size = 100000)
        ).astype(int),
        range = (0.5, 5.5), bins = 50, density = True)
plt.show()

以下是实际参数化的结果:

# Actual target case
a = 890
b = 3200
c = 2600
plt.hist(np.ma.round(np.random.triangular(
          left = a - 0.5,
          mode = c,
          right = b + 0.5, 
          size = 100000)
        ).astype(int),
        range = (500, 3500), bins = 300, density = True)
plt.show()

请注意,与 cmets 中建议的正态分布不同,它保证保持在 (a, b) 范围内。

【讨论】:

    【解决方案2】:

    你使用

    random.choices(range(a,b+1), weights= [....], k=1)  # or cum_weights
    

    对于 1 的 krange(a,b+1) 中的人口以及您想要的权重。

    见:https://docs.python.org/3/library/random.html#random.choices


    您必须计算可能的(任意)权重 f.e.:

    import random
    from collections import defaultdict
    a = 8
    b = 32
    
    c = 26
    
    # hacked distribution
    w = [(i-a)**2 if i <= c else (b-i+a)**2 for i in range(a,b+1)]
    
    d=defaultdict(int)
    for i in range(a,b+1):
        d[i]=0
    
    # test for 10k numbers
    for num in random.choices(range(a,b+1), weights = w, k=10000):
        d[num] += 1
    
    print(w)
    print(d)
    

    它仍然是随机的,一次运行让我:

    # hacked distribution
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 
      256, 289, 196, 169, 144, 121, 100, 81, 64]
    
    # test for 10k numbers
    {8: 0, 9: 8, 10: 7, 11: 37, 12: 61, 13: 94, 14: 149, 15: 175, 16: 229, 
     17: 283, 18: 374, 19: 450, 20: 493, 21: 628, 22: 672, 23: 820, 24: 907, 
     25: 1038, 26: 1183, 27: 564, 28: 537, 29: 435, 30: 325, 31: 293, 32: 238}
    

    【讨论】:

    • 他们没有一堆权重,只是一个模式。因此,选择和缩放具有预期属性的统计分布可能是解决方案。
    • 正如 Masklinn 已经提到的,我没有为我的范围内的每个可能状态设置权重 - 因此,我无法为 random.choices 设置权重。还是我错了?
    • @mask 他必须计算分布,见编辑。
    猜你喜欢
    • 2022-01-19
    • 2018-06-23
    • 1970-01-01
    相关资源
    最近更新 更多