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?
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)
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:
accumulate
pour créer des bacs.0
Et 1
) En utilisant random_sample
digitize
pour voir dans quels casiers ces nombres entrent.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.
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à!
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.