J'utilise x = numpy.random.rand(1) pour générer un nombre aléatoire entre 0 et 1. Comment faire en sorte que x > .5 soit 2 fois plus probable que x < .5?

22
random 16 juil. 2015 à 21:52

6 réponses

Meilleure réponse

Voilà un nom approprié!

Faites juste une petite manipulation des entrées. Définissez d'abord x pour qu'il soit compris entre 0 et 1.5.

x = numpy.random.uniform(1.5)

x a 2/3 chance d'être supérieur à 0.5 et 1/3 chance d'être plus petit. Ensuite, si x est supérieur à 1.0, soustrayez-y .5

if x >= 1.0:
    x = x - 0.5
28
Samrat Dutta 28 juil. 2015 à 19:04

Si vous voulez un caractère aléatoire plus fluide, vous pouvez juste mettre au carré la sortie de la fonction aléatoire

(et soustrayez-le de 1 pour rendre x > 0.5 plus probable au lieu de x < 0.5).

x = 1 - sqr(numpy.random.rand(1))
0
Mystery 16 juil. 2015 à 20:44

Vous pouvez adopter une approche de «modèle de mélange» où vous divisez le processus en deux étapes: premièrement, décidez si vous devez prendre l'option A ou B, où B est deux fois plus probable que A; puis, si vous avez choisi A, renvoyez un nombre aléatoire entre 0,0 et 0,5, sinon si vous avez choisi B, renvoyez-en un entre 0,5 et 1,0.

Dans l'exemple, le randint renvoie au hasard 0, 1 ou 2, donc le cas else est deux fois plus probable que le cas if.

  m = numpy.random.randint(3)
  if m==0:
    x = numpy.random.uniform(0.0, 0.5)
  else:
    x = numpy.random.uniform(0.5, 1.0)

C'est un peu plus cher (deux tirages aléatoires au lieu d'un) mais cela peut se généraliser à des distributions plus compliquées d'une manière assez simple.

1
gnarledRoot 17 juil. 2015 à 02:38

Tout d'abord, numpy.random.rand(1) ne renvoie pas de valeur dans la plage [0,1) (semi-ouvert, inclut zéro mais pas un), il renvoie un tableau de taille un, contenant des valeurs dans cette plage, l'extrémité supérieure de la plage n'ayant rien à voir avec l'argument transmis.

La fonction que vous recherchez probablement est celle à distribution uniforme, numpy.random.uniform() car cela permettra une plage supérieure arbitraire.

Et, rendre la moitié supérieure deux fois plus probable est une question relativement simple.

Prenons, par exemple, un générateur de nombres aléatoires r(n) qui renvoie un entier uniformément distribué dans la plage [0,n). Il vous suffit d'ajuster les valeurs pour modifier la distribution:

x = r(3)     # 0, 1 or 2, @ 1/3 probability each
if x == 2:
    x = 1    # Now either 0 (@ 1/3) or 1 (@ 2/3)

Maintenant, les chances d'obtenir zéro sont 1/3 tandis que les chances d'en obtenir un sont 2/3, essentiellement ce que vous essayez d'atteindre avec vos valeurs à virgule flottante.

Je voudrais donc simplement obtenir un nombre aléatoire dans la plage [0,1.5), puis soustraire 0,5 s'il est supérieur ou égal à un.

x = numpy.random.uniform(high=1.5)
if x >= 1: x -= 0.5

Étant donné que la distribution d'origine doit être uniforme sur la plage [0,1.5), la soustraction doit rendre [0.5,1.0) deux fois plus probable (et [1.0,1.5) impossible), tout en conservant la distribution même dans chaque section ({{X3 }} et [0.5,1)):

 [0.0,0.5)  [0.5,1.0)  [1.0,1.5)  before
<---------><---------><--------->
 [0.0,0.5)  [0.5,1.0)  [0.5,1.0)  after
3
paxdiablo 17 juil. 2015 à 02:34
tmp = random()
if tmp < 0.5: tmp = random()

Est un moyen assez facile de le faire

Ehh je suppose que c'est 3x plus probable ... c'est ce que j'obtiens pour dormir dans cette classe, je suppose

from random import random,uniform

def rand1():
    tmp = random()
    if tmp < 0.5:tmp = random()
    return tmp
def rand2():
    tmp = uniform(0,1.5)
    return tmp if tmp <= 1.0 else tmp-0.5

sample1 = []
sample2 = []
for i in range(10000):
    sample1.append(rand1()>=0.5)
    sample2.append(rand2()>=0.5)

print sample1.count(True) #~ 75% 
print sample2.count(True) #~ 66% <- desired i believe :)
8
Joran Beasley 16 juil. 2015 à 19:36

C'est exagéré pour vous, mais il est bon de connaître une méthode réelle pour générer un nombre aléatoire avec n'importe quelle fonction de densité de probabilité (pdf).

Vous pouvez le faire en sous-classant scipy.stat.rv_continuous, à condition de le faire correctement. Vous devrez avoir un pdf normalisé (pour que son intégrale soit 1). Sinon, numpy ajustera automatiquement la plage pour vous. Dans ce cas, votre pdf a une valeur de 2/3 pour x <0,5, et 4/3 pour x> 0,5, avec un support de [0, 1) (le support est l'intervalle sur lequel il est différent de zéro):

import scipy.stats as spst
import numpy as np
import matplotlib.pyplot as plt
import ipdb


def pdf_shape(x, k):
    if x < 0.5:
        return 2/3.
    elif 0.5 <= x and x < 1:
        return 4/3.
    else:
        return 0.


class custom_pdf(spst.rv_continuous):
    def _pdf(self, x, k):
        return pdf_shape(x, k)

instance = custom_pdf(a=0, b=1)

samps = instance.rvs(k=1, size=10000)

plt.hist(samps, bins=20)
plt.show()

Example histogram

16
Joel 31 mai 2019 à 21:11