web-dev-qa-db-fra.com

Génération de variables aléatoires discrètes avec des poids spécifiés à l'aide de SciPy ou NumPy

Je recherche une fonction simple qui peut générer un tableau de valeurs aléatoires spécifiées en fonction de leurs probabilités correspondantes (également spécifiées). Je n'en ai besoin que pour générer des valeurs flottantes, mais je ne vois pas pourquoi il ne devrait pas pouvoir générer de scalaire. Je peux penser à de nombreuses façons de construire cela à partir de fonctions existantes, mais je pense que je viens de manquer une fonction SciPy ou NumPy évidente.

Par exemple.:

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

Remarque: j'ai trouvé scipy.stats.rv_discrete mais je ne comprends pas comment cela fonctionne. Plus précisément, je ne comprends pas ce que cela (ci-dessous) signifie ni ce qu'il devrait faire:

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

Si rv_discrete est ce que je devrais utiliser, pourriez-vous me fournir un exemple simple et une explication de la déclaration de "forme" ci-dessus?

41
TimY

Le dessin à partir d'une distribution discrète est directement intégré à numpy. La fonction est appelée random.choice (difficile à trouver sans référence à des distributions discrètes dans les documents numpy).

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

Voici une fonction courte et relativement simple qui renvoie des valeurs pondérées, elle utilise digitize, accumulate et random_sample De NumPy.

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]

Cela fonctionne comme ceci:

  1. Nous utilisons d'abord accumulate pour créer des bacs.
  2. Ensuite, nous créons un tas de nombres aléatoires (entre 0 Et 1) En utilisant random_sample
  3. Nous utilisons digitize pour voir dans quels casiers ces nombres entrent.
  4. Et renvoyez les valeurs correspondantes.
25
fraxel

Vous alliez dans la bonne direction: le scipy.stats.rv_discrete() intégré crée assez directement une variable aléatoire discrète. Voici comment cela fonctionne:

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

La distribution distrib ci-dessus renvoie donc index de la liste values.

Plus généralement, rv_discrete() prend une séquence de valeurs entier dans les premiers éléments de son argument values=(…,…), et renvoie ces valeurs, dans ce cas; il n'est pas nécessaire de convertir en valeurs spécifiques (float). Voici un exemple:

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

où les valeurs d'entrée (entières) sont directement renvoyées avec la probabilité souhaitée.

15
Eric O Lebigot

Vous pouvez également utiliser Lea , un package pur Python dédié aux distributions de probabilités discrètes.

>>> 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à!

4
Pierre Denis

La méthode de bricolage la plus simple serait de résumer les probabilités en une distribution cumulative. De cette façon, vous divisez l'intervalle unitaire en sous-intervalles de la longueur égale à vos probabilités d'origine. Générez maintenant un seul nombre aléatoire uniforme sur [0,1) et voyez à quel intervalle il atterrit.

3
ev-br