J'ai un fichier avec quelques probabilités pour différentes valeurs par exemple:
1 0.1
2 0.05
3 0.05
4 0.2
5 0.4
6 0.2
Je voudrais générer des nombres aléatoires en utilisant cette distribution. Existe-t-il un module existant qui gère cela? Il est assez simple de coder vous-même (construire la fonction de densité cumulative, générer une valeur aléatoire [0,1] et choisir la valeur correspondante) mais il semble que cela devrait être un problème courant et probablement quelqu'un a créé une fonction / module pour il.
J'en ai besoin car je veux générer une liste d'anniversaires (qui ne suivent aucune distribution dans le random
module standard ).
random.choice()
? Vous construisez la liste principale avec le nombre approprié d'occurrences et en choisissez une. C'est une question en double, bien sûr.Réponses:
scipy.stats.rv_discrete
pourrait être ce que vous voulez. Vous pouvez fournir vos probabilités via levalues
paramètre. Vous pouvez ensuite utiliser larvs()
méthode de l'objet de distribution pour générer des nombres aléatoires.Comme indiqué par Eugene Pakhomov dans les commentaires, vous pouvez également passer un
p
paramètre de mot - clé ànumpy.random.choice()
, par exempleSi vous utilisez Python 3.6 ou supérieur, vous pouvez utiliser à
random.choices()
partir de la bibliothèque standard - voir la réponse de Mark Dickinson .la source
numpy.random.choice()
c'est presque 20 fois plus rapide.numpy.random.choice(numpy.arange(1, 7), p=[0.1, 0.05, 0.05, 0.2, 0.4, 0.2])
Depuis Python 3.6, il existe une solution pour cela dans la bibliothèque standard de Python, à savoir
random.choices
.Exemple d'utilisation: définissons une population et des poids correspondant à ceux de la question du PO:
Génère maintenant
choices(population, weights)
un seul échantillon:L'argument facultatif de mot-clé uniquement
k
permet de demander plus d'un échantillon à la fois. Ceci est précieux car il y a un travail préparatoirerandom.choices
à faire à chaque fois qu'il est appelé, avant de générer des échantillons; en générant plusieurs échantillons à la fois, nous n'avons à faire ce travail préparatoire qu'une seule fois. Ici, nous générons un million d'échantillons et utilisonscollections.Counter
pour vérifier que la distribution que nous obtenons correspond approximativement aux poids que nous avons donnés.la source
Un avantage de la génération de la liste à l'aide de CDF est que vous pouvez utiliser la recherche binaire. Bien que vous ayez besoin de temps et d'espace O (n) pour le prétraitement, vous pouvez obtenir k nombres dans O (k log n). Les listes Python normales étant inefficaces, vous pouvez utiliser
array
module.Si vous insistez sur un espace constant, vous pouvez faire ce qui suit; O (n) temps, O (1) espace.
la source
l[-1]
renvoie le dernier élément de la liste?Il est peut-être un peu tard. Mais vous pouvez utiliser
numpy.random.choice()
, en passant lep
paramètre:la source
random.choice()
- voir les commentaires.numpy.random.choice()
est complètement différent derandom.choice()
et prend en charge la distribution de probabilité.(OK, je sais que vous demandez du film rétractable, mais peut-être que ces solutions locales n'étaient tout simplement pas assez succinctes à votre goût. :-)
J'ai pseudo-confirmé que cela fonctionne en regardant la sortie de cette expression:
la source
i
n'est pas un objet.J'ai écrit une solution pour tirer des échantillons aléatoires à partir d'une distribution continue personnalisée .
J'en avais besoin pour un cas d'utilisation similaire au vôtre (c'est-à-dire générer des dates aléatoires avec une distribution de probabilité donnée).
Vous avez juste besoin de la fonction
random_custDist
et de la lignesamples=random_custDist(x0,x1,custDist=custDist,size=1000)
. Le reste est de la décoration ^^.Les performances de cette solution sont certes améliorables, mais je préfère la lisibilité.
la source
Faites une liste d'articles, en fonction de leur
weights
:Une optimisation peut consister à normaliser les montants par le plus grand diviseur commun, afin de réduire la liste cible.
En outre, cela pourrait être intéressant.
la source
Une autre réponse, probablement plus rapide :)
la source
Vérification:
la source
basé sur d'autres solutions, vous générez une distribution cumulative (sous forme d'entier ou de flottant comme vous le souhaitez), puis vous pouvez utiliser la bissectrice pour la rendre rapide
ceci est un exemple simple (j'ai utilisé des entiers ici)
la
get_cdf
fonction le convertirait de 20, 60, 10, 10 en 20, 20 + 60, 20 + 60 + 10, 20 + 60 + 10 + 10maintenant nous choisissons un nombre aléatoire jusqu'à 20 + 60 + 10 + 10 en utilisant
random.randint
puis nous utilisons la bissectrice pour obtenir la valeur réelle de manière rapidela source
vous voudrez peut-être jeter un œil aux distributions d'échantillonnage aléatoire NumPy
la source
Aucune de ces réponses n'est particulièrement claire ou simple.
Voici une méthode claire et simple qui garantit son efficacité.
accumulate_normalize_probabilities prend un dictionnaire
p
qui mappe les symboles aux probabilités OU aux fréquences. Il génère une liste utilisable de tuples à partir de laquelle effectuer la sélection.Rendements:
Pourquoi ça marche
L' étape d' accumulation transforme chaque symbole en un intervalle entre lui-même et la probabilité ou la fréquence des symboles précédents (ou 0 dans le cas du premier symbole). Ces intervalles peuvent être utilisés pour sélectionner (et donc échantillonner la distribution fournie) en parcourant simplement la liste jusqu'à ce que le nombre aléatoire dans l'intervalle 0,0 -> 1,0 (préparé plus tôt) soit inférieur ou égal au point final de l'intervalle du symbole actuel.
La normalisation nous libère du besoin de nous assurer que tout a une certaine valeur. Après normalisation, le «vecteur» des probabilités est égal à 1,0.
Le reste du code pour la sélection et la génération d'un échantillon arbitrairement long à partir de la distribution est ci-dessous:
Utilisation:
la source
Voici un moyen plus efficace de procéder:
Appelez simplement la fonction suivante avec votre tableau «poids» (en supposant que les indices sont les éléments correspondants) et le no. d'échantillons nécessaires. Cette fonction peut être facilement modifiée pour gérer une paire ordonnée.
Renvoie les index (ou éléments) échantillonnés / sélectionnés (avec remplacement) en utilisant leurs probabilités respectives:
Une brève note sur le concept utilisé dans la boucle while. Nous réduisons le poids de l'élément actuel à partir du bêta cumulatif, qui est une valeur cumulée construite uniformément au hasard, et incrémentons l'indice actuel afin de trouver l'élément dont le poids correspond à la valeur de bêta.
la source