Вопрос по numpy, scipy, random, python – Генерация дискретных случайных величин с заданными весами с использованием SciPy или NumPy

39

Я ищу простую функцию, которая может генерировать массив указанных случайных значений на основе их соответствующих (также указанных) вероятностей. Он мне нужен только для генерации значений с плавающей точкой, но я не понимаю, почему он не может генерировать какой-либо скаляр. Я могу придумать много способов построить это из существующих функций, но я думаю, что я, вероятно, просто пропустил очевидную функцию 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, не могли бы вы предоставить мне простой пример и объяснение вышеприведенной «формы»? заявление?

Ваш Ответ

5   ответов
3

ное распределение. Таким образом, вы разделяете единичный интервал на подинтервалы длины, равной вашим первоначальным вероятностям. Теперь сгенерируйте единое случайное число на [0,1) и посмотрите, к какому интервалу оно попадет.

Да, это в основном то, о чем я думал, но я просто подумал, что может быть встроенная функция, которая делает именно это. Судя по всему, такого нет. TimY
24

относительно простая функция, которая возвращает взвешенные значения, она использует NumPydigitize, 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]

Это работает так:

First using accumulate we create bins. Then we create a bunch of random numbers (between 0, and 1) using random_sample We use digitize to see which bins these numbers fall into. And return the corresponding values.
Нужно ли нормировать вероятности для этого?
PS: & # x2026; Как отметил Tim_Y, использование функции SciPy намного медленнее, чем использование вашего «руководства». решение (по 10к элементов).
+1 за полезноеnumpy.digitize()! Однако SciPy фактически предлагает функцию, которая напрямую отвечает на вопрос & # x2014; см. Мой ответ.
Да, это в основном то, о чем я думал, но я просто подумал, что может быть встроенная функция, которая делает именно это. Судя по всему, такого нет. Я должен признать - я бы не сделал это так элегантно. - Спасибо TimY
NumPy напрямую предлагаетnumpy.cumsum(), который можно использовать вместоnp.add.accumulate() (np.add() не очень часто используется, поэтому я рекомендую использоватьcumsum()).
53

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

elements = [1.1, 2.2, 3.3]
probabilities = [0.2, 0.5, 0.3]
np.random.choice(elements, 10, p=probabilities)
Большой! Но правильный синтаксис: np.random.choice (elements, 10, p = list (вероятности))
Очень хорошо! Кажется, работает и без приведения к списку: np.random.choice (elements, 10, p = вероятности)).
В дополнение к комментариямSina а такжеzeycus, elements а такжеprobabilites мог бы быть обычнымlistс вместоnumpy.arrayи код будет работать одинаково.
Ницца. Я думаю, что эта версия вышла после того, как я опубликовал свой оригинальный вопрос (я думаю, что он был впервые выпущен в 1.7.0, который, как я считаю, появился в 2013 году). TimY
4

лугчистый пакет 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 & # xE0 ;!

15

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 выше, таким образом, возвращаетindexes отvalues список.

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

>>> 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])

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

@ Tim, мое наивное предположение, заключается в том, что медлительность объясняется тем, что в чистом Python выполняется больше работы, а в C. - меньше работы (под капотом) (математические / научные пакеты в Python, как правило, оборачивают код C).
@dbliss Теперь я вижу, что вы имели в виду случай дискретного распределения сinfinite количество возможных значений (что не вписывается в этот вопрос).rv_discrete() не имеет возможности для этого. Я не уверен, что стандартный метод для этого. (Я могу только думать о слегка усложненных вариациях обычного метода, который преобразует однородную случайную переменную в переменную с неравномерным распределением, где совокупная вероятность рассчитывается только для наиболее распространенных значений и при необходимости расширяется за пределы.)
ПРИМЕЧАНИЕ. Я попытался запустить timeit на нем, и, похоже, он в 100 раз медленнее, чем просто непонятная версия fraxel. Вы случайно не знаете, почему это так? TimY
Предположим, я должен был начать с уравнения для моего распределения вероятностей. кажется глупым использовать это, чтобы генерировать вероятность для каждого значения, скормить этоrv_discrete, а затем вернуться изrv_discrete приближение распределения, с которого я начал. Есть ли способ использовать пользовательские уравнения непосредственно сscipy?

Похожие вопросы