Jump to content

Gerar um lancamento de um dado Viciado


Recommended Posts

Posted

Pessoal estou mesmo com grande duvida nisto...

Eu sei gerar numeros pseudo-aleatorios com o python através do randint e por ai fora...

Mas como posso gerar numeros que dependem de probabilidades?

Segue o problema em questao:

A probabilidade de sair de 1 a 5 = 1/6

A probabilidade de sair 6 = 1/3

Como faço para gerar isto? Não estou mesmo a ver :S (?)

Posted

Crias uma lista com as probabilidades associadas a cada valor, e de seguida calculas a função de distribuição associada (i.e. a soma cumulativa dos valores das probabilidades):

pb = [0.2, 0.2, 0.2, 0.25, 0.1]
pc = []
s = 0
for p in pb:
 s+=p
 pc.append(s)

Depois basta gerares um número real "r" uniformemente distribuído entre 0 e 1 e devolver i+1 em que "i" é o menor tal que pc >= r. Isto pode ser feito percorrendo a lista pc ou com pesquisa binária.

P.S.: As probabilidades nesse teu problema não somam 1. Verifica isso.

Não respondo a dúvidas por mensagem.

Posted

Segue o problema em questao:

A probabilidade de sair de 1 a 5 = 1/6

A probabilidade de sair 6 = 1/3

Pois, tal como o @pedrosorio referiu, 1 - (1/6 + 1/3) = 1/2: este 1/2 de probabilidade que resta refere-se a que acontecimento? Não falta aqui algo?

@pedrosorio, a tua lista pb também não soma 1, soma 0.95 xD

Em termos de programação, não bastaria criar uma lista com os valores de tal forma que a Lei de Laplace se aplicasse? Imaginemos que P(1..5)=2/3 e P(6)=1/3:

p = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 6]
random.choice(p)

Yah, eu não sou grande espingarda a probabilidades e estatística, pelo que a tua solução, apesar de com esses dados que deste saber o que fazer, não a entendi em termos "teóricos", pelo que estava a tentar encontrar uma solução mais "caseira" 😄

Knowledge is free!

Posted (edited)

Afinal a solução era bem mais simples enfim LOL

def dadoviciado():
   x=randint(1,7)
   if x>=6:
       return 6
   else:
       return x

print dadoviciado()
Edited by thoga31
GeSHi
Posted

"Flames" acho que o código que meteste não é o de um dado viciado. Tanto a solução que o pedrosorio ou o thoga31 deram resultam, a meu ver, bastante bem. O randint que estás a fazer (se é a função que estou a pensar) só vai dar valores de 1 a 6 pelo que o "if" que fazes depois é redundante.

Pessoalmente para melhor controlo de uma distribuição da probabilidade de dados eu usaria a cumulada (numpy -> import numpy as np):

In [44]: a = [0.2, 0.2, 0.2, 0.25, 0.1, 0.05]

In [45]: np.cumsum(a)
Out[45]: array([ 0.2 ,  0.4 ,  0.6 ,  0.85,  0.95, 0.05  ])

A partir daqui gerava um valor de 0 a 1:

In [66]: np.random.rand()
Out[66]: 0.7913770726057889

Como o meu valor está entre 0.6 e 0.85 o resultado seria 5 (se fosse 0.23, por exemplo, seria 2 e por ai adiante).

Posted (edited)

"Flames" acho que o código que meteste não é o de um dado viciado. Tanto a solução que o pedrosorio ou o thoga31 deram resultam, a meu ver, bastante bem. O randint que estás a fazer (se é a função que estou a pensar) só vai dar valores de 1 a 6 pelo que o "if" que fazes depois é redundante.

Sim, a solução é totalmente redundante. Só faria sentido se o range dado ao randint fosse maior do que 7, aliás, se fosse um número muito específico, para cumprir as probabilidades. E mesmo assim não seria a solução "ideal".

Pessoalmente para melhor controlo de uma distribuição da probabilidade de dados eu usaria a cumulada (numpy -> import numpy as np):

Traceback (most recent call last):
 File "<pyshell#1>", line 1, in <module>
   import numpy as np
ImportError: No module named numpy

Deixo, então, uma possível implementação do cumsum:

def cumsum(l):
   return [l[i] + sum(l[:i]) for i in range(len(l))]

A partir daqui gerava um valor de 0 a 1:

In [66]: np.random.rand()
Out[66]: 0.7913770726057889

Como o meu valor está entre 0.6 e 0.85 o resultado seria 5 (se fosse 0.23, por exemplo, seria 2 e por ai adiante).

Com a lista inicial definida com as probabilidades pretendidas, este método é o ideal.

E agora já entendi o que o @pedrosorio tinha dito xD

Edited by thoga31

Knowledge is free!

Posted

Vocês são muito bons rapazes, mas no caso em apreço** podemos simplificar 🙂

def wth(): return 6 if random.uniform(0,1) < 1/3.0 else random.randint(1,5)

** considerando 1/3 para sair 6, o resto para 1 a 5

Posted

E atenção que a solução do flames até nem está mal pensada -- n.b. o randint(a,b) retorna de 'a' a 'b' inclusive -- mas a implementação dá 2/7 para o 6 e 1/7 para cada de 1 a 5, i.e. diferente dos valores iniciais.

Posted

@pedrosorio, a tua lista pb também não soma 1, soma 0.95 xD

Pois não. Estava com pressa e nem reparei...

Em termos de programação, não bastaria criar uma lista com os valores de tal forma que a Lei de Laplace se aplicasse? Imaginemos que P(1..5)=2/3 e P(6)=1/3:

p = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 6]
random.choice(p)

Yah, eu não sou grande espingarda a probabilidades e estatística, pelo que a tua solução, apesar de com esses dados que deste saber o que fazer, não a entendi em termos "teóricos", pelo que estava a tentar encontrar uma solução mais "caseira" 😄

Isso é possível mas é fácil tornar-se inviável se tiveres probabilidades com um grande número de casas decimais.

Imagina que tens as probabilidades de cada acontecimento em p. Se tiveres a soma cumulativa das probabilidades em pc (e, ao contrário do que fiz no meu exemplo vamos supôr que acrescentamos um 0 no início de pc), vamos ter p[0] = 0 e p[N] = 1. Ao gerar um número aleatório uniforme entre 0 e 1, a probabilidade de ele calhar entre o valor pc e o valor pc[i+1] é precisamente pc[i+1] - pc. Como pc é a soma cumulativa de p, pc[i+1] - pc = p (isto porque acrescentámos um 0 no início do pc).

Repara então que quando o número aleatório gerado for entre p e p[i+1], podemos escolher o i-ésimo resultado e a probabilidade de o fazermos é a correcta (p ). Isto vale para todos os acontecimentos.

P.S.: Ia agora colocar aqui um exemplo mas já li que percebeste entretanto. A forma como chegamos ao "i" a partir do valor aleatório pode ser percorrendo a lista linearmente ou com pesquisa binária. Curiosamente existe também um método que permite gerar números aleatórios de uma distribuição discreta em O(1): http://infoweekly.blogspot.pt/2011/09/follow-up-sampling-discrete.html

Não respondo a dúvidas por mensagem.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.