Подтвердить что ты не робот

Создание дискретных случайных величин с заданными весами с использованием SciPy или NumPy

Я ищу простую функцию, которая может генерировать массив заданных случайных значений на основе их соответствующих (также заданных) вероятностей. Мне нужно только его генерировать значения float, но я не понимаю, почему он не должен генерировать никакого скаляра. Я могу думать о многих способах построения этого из существующих функций, но я думаю, что, вероятно, просто пропустил очевидную функцию SciPy или NumPy.

например:.

>>> values = [1.1, 2.2, 3.3]
>>> probabilities = [0.2, 0.5, 0.3]
>>> print some_function(values, probabilities, size=10)
(2.2, 1.1, 3.3, 3.3, 2.2, 2.2, 1.1, 2.2, 3.3, 2.2)

Примечание. Я нашел scipy.stats.rv_discrete, но я не понимаю, как это работает. В частности, я не понимаю, что означает это (ниже), и что он должен делать:

numargs = generic.numargs
[ <shape(s)> ] = ['Replace with resonable value', ]*numargs

Если rv_discrete - это то, что я должен использовать, не могли бы вы предоставить мне простой пример и объяснение вышеприведенного утверждения "shape"?

4b9b3361

Ответ 1

Рисование из дискретного распределения напрямую встроено в numpy. Функция называется random.choice (трудно найти без какой-либо ссылки на дискретные распределения в документах numpy).

elements = [1.1, 2.2, 3.3]
probabilities = [0.2, 0.5, 0.3]
np.random.choice(elements, 10, p=probabilities)

Ответ 2

Вот короткая, относительно простая функция, возвращающая взвешенные значения, она использует NumPy digitize, accumulate и random_sample.

import numpy as np
from numpy.random import random_sample

def weighted_values(values, probabilities, size):
    bins = np.add.accumulate(probabilities)
    return values[np.digitize(random_sample(size), bins)]

values = np.array([1.1, 2.2, 3.3])
probabilities = np.array([0.2, 0.5, 0.3])

print weighted_values(values, probabilities, 10)
#Sample output:
[ 2.2  2.2  1.1  2.2  2.2  3.3  3.3  2.2  3.3  3.3]

Он работает следующим образом:

  • Сначала с помощью accumulate создаем корзины.
  • Затем мы создаем кучу случайных чисел (между 0 и 1), используя random_sample
  • Мы используем digitize, чтобы увидеть, в какие ячейки входят эти числа.
  • И верните соответствующие значения.

Ответ 3

Вы шли в хорошем направлении: встроенный scipy.stats.rv_discrete() вполне создает дискретную случайную переменную. Вот как это работает:

>>> from scipy.stats import rv_discrete  

>>> values = numpy.array([1.1, 2.2, 3.3])
>>> probabilities = [0.2, 0.5, 0.3]

>>> distrib = rv_discrete(values=(range(len(values)), probabilities))  # This defines a Scipy probability distribution

>>> distrib.rvs(size=10)  # 10 samples from range(len(values))
array([1, 2, 0, 2, 2, 0, 2, 1, 0, 2])

>>> values[_]  # Conversion to specific discrete values (the fact that values is a NumPy array is used for the indexing)
[2.2, 3.3, 1.1, 3.3, 3.3, 1.1, 3.3, 2.2, 1.1, 3.3]

Таким образом, распределение distrib выше возвращает индексы из списка values.

В более общем плане rv_discrete() принимает последовательность целочисленных значений в первых элементах своего аргумента values=(…,…) и возвращает эти значения в этом случае; нет необходимости конвертировать в конкретные (float) значения. Вот пример:

>>> values = [10, 20, 30]
>>> probabilities = [0.2, 0.5, 0.3]
>>> distrib = rv_discrete(values=(values, probabilities))
>>> distrib.rvs(size=10)
array([20, 20, 20, 20, 20, 20, 20, 30, 20, 20])

где (целочисленные) входные значения напрямую возвращаются с желаемой вероятностью.

Ответ 4

Вы также можете использовать Lea, чистый пакет Python, предназначенный для дискретных распределений вероятностей.

>>> distrib = Lea.fromValFreqs((1.1,2),(2.2,5),(3.3,3))
>>> distrib
1.1 : 2/10
2.2 : 5/10
3.3 : 3/10
>>> distrib.random(10)
(2.2, 2.2, 1.1, 2.2, 2.2, 2.2, 1.1, 3.3, 1.1, 3.3)

Et voilà!

Ответ 5

Самый простой способ DIY - суммировать вероятности в кумулятивное распределение. Таким образом, вы разбиваете единицу интервала на промежутки времени, равные исходным вероятностям. Теперь создадим одно случайное число, равномерное на [0,1), и посмотрим, к какому интервалу он приземляется.