Flames Posted October 22, 2012 at 11:20 PM Report #480051 Posted October 22, 2012 at 11:20 PM 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 (?)
pedrosorio Posted October 23, 2012 at 07:43 AM Report #480057 Posted October 23, 2012 at 07:43 AM 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.
thoga31 Posted October 23, 2012 at 01:32 PM Report #480079 Posted October 23, 2012 at 01:32 PM 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!
Flames Posted October 23, 2012 at 03:34 PM Author Report #480098 Posted October 23, 2012 at 03:34 PM (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 October 23, 2012 at 07:41 PM by thoga31 GeSHi
Pedro C. Posted October 23, 2012 at 06:02 PM Report #480128 Posted October 23, 2012 at 06:02 PM "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).
thoga31 Posted October 23, 2012 at 07:50 PM Report #480145 Posted October 23, 2012 at 07:50 PM (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 October 23, 2012 at 07:52 PM by thoga31 Knowledge is free!
motherFFH Posted October 23, 2012 at 09:41 PM Report #480166 Posted October 23, 2012 at 09:41 PM 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
motherFFH Posted October 23, 2012 at 09:51 PM Report #480168 Posted October 23, 2012 at 09:51 PM 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.
thoga31 Posted October 23, 2012 at 09:56 PM Report #480172 Posted October 23, 2012 at 09:56 PM def wth(): return 6 if random.uniform(0,1) < 1/3.0 else random.randint(1,5) Também está bem pensado para este caso. Mas para um caso mais geral já terás de expandir. 😉 Knowledge is free!
pedrosorio Posted October 23, 2012 at 10:38 PM Report #480177 Posted October 23, 2012 at 10:38 PM @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.
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now