Взвешенная версия random.randint - PullRequest
0 голосов
/ 26 марта 2020

Я хотел бы выбрать случайное целое число от a до b (оба включены), со статистическим весом c.

c - это значение между a и b.

Какой самый эффективный способ применить весовой коэффициент c к random.randint?

Самый близкий я получил этот вопрос, но есть большая разница:

У меня есть только один статистический вес c, а не статистическая вероятность для каждого значения между a и b.

Пример:

a = 890
b = 3200

c = 2600

print(random.randint(a,b))

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

Меня не волнует распределение между a и b, пока на c есть вес. Однако, распределение по Гауссу приветствуется.

Обратите внимание: этот вопрос не не относится к модулю numpy.random, как в этом вопросе.

Ответы [ 2 ]

1 голос
/ 26 марта 2020

Похоже, что tri angular дистрибутив может соответствовать вашим потребностям. Значения a и b являются min и max соответственно, а c соответствует режиму (наиболее вероятный результат) распределение.

В numpy.random есть генератор tri angular. Он генерирует числа с плавающей точкой, но вы можете округлить и затем объединить результаты. Если вы придирчивы, это будет слегка смещено от минимума и максимума, которые будут иметь только половину диапазона и, следовательно, половину ожидаемого числа по сравнению с другими целочисленными значениями. Статистики корректируют это преобразование диапазона из действительных в целые, используя исправление непрерывности : вычтите 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()

Histogram of generated triangular distribution

Обратите внимание, что в отличие от нормального распределения, предложенного в комментариях, оно гарантированно останется в диапазоне (a, b).

0 голосов
/ 26 марта 2020

Вы используете

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

для k из 1 и совокупности в range(a,b+1) и желаемых весов.

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


Вы должны рассчитать возможный (произвольный) весовой коэффициент, например:

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}
...