[Python-es] ¿Cómo generar una distribución aleatoria?

lasizoillo lasizoillo en gmail.com
Mie Jul 3 18:46:25 EDT 2019


Buenas,

Tras leer el correo de Chema me puse a pensar en cuantos bits de
información se podía obtener de randint(1,5) y cuantos necesitaba
randint(1,7) y me dio por pensar que era ln2(5) y ln2(7). Lo cual
seguramente es incorrecto (las mates no son lo mío), pero aun siendo una
estimación menor que el ideal propuesto por Chema de 1.4 llamadas es mayor
al usado en la solución de Mario (1). Así que había pensado en hacer unos
tests de aleatoriedad sobre esa solución demasiado bonita para ser cierta,
pero gracias por adelantarte.

¿Se deberían descartar todas las soluciones que hagan menos de 1.2 o 1.4
llamadas a randint(1,5) para calcular randint(1,7)?

De todas formas aunque he encontrado formas de hacer algo más eficiente mi
solución, no se me ha ocurrido nada digno de mención y por ahora están muy
lejos de 1.4 llamadas.

Un saludo,

Javi

El mié., 3 jul. 2019 a las 21:00, Daπid (<davidmenhur en gmail.com>) escribió:

> Distribución plana es sólo uno de los requisitos de randint. Otro es que
> los valores sucesivos sean independientes.
>
> La solución de Mario tiene este problema:
>
> import numpy as np
> import pylab as plt
>
> results = []
> k, seed = randint_1_7()
> for n in range(100000):
>     k, seed = randint_1_7(seed)
>     results.append(k)
>
> results = np.array(results)
> plt.hist2d(results[::2], results[1::2], bins=(np.arange(1, 8)-0.5,
> np.arange(1,8)-0.5))
> plt.colorbar()
> plt.scatter(results[::2], results[1::2], color='w')
> plt.tight_layout()
> [image: hist_randint.png]
>
> Como puedes ver, nunca tienes dos números iguales seguidos, y nunca tienes
> un número seguido del anterior.
>
> El mismo proceso en tres dimensiones revela más agujeros.
>
> La solución de Lasizoillo parece no tener este problema.
>
>
> Detalle importante: este es un test muy básico de independencia, que lo
> pase no quiere decir que sea independiente...
>
> /David.
>
> On Wed, 3 Jul 2019 at 18:07, Mario R. Osorio <nimbiotics en gmail.com> wrote:
>
>> Muy interesante la solución de Javi (Que demuestra tener una distribución
>> plana), sin embargo me permito presentar la mía para su consideración:
>>
>> """
>>  Solucion para:
>>     generar una distribución plana de enteros aleatorios, del 1 al 7,
>> usando únicamente random.randint(1,5)
>>     como funcion generadora de enteros aleatorios
>> """
>>
>> from random import randint
>>
>> def randint_1_7(seed=None):
>>     l = (1, 2, 3, 4, 5, 6, 7)
>>
>>     if seed is None:
>>         seed = randint(1,5) + randint(1,5)
>>     else:
>>         seed += randint(1,5)
>>
>>     seed = seed % 7
>>
>>     return (l[seed - 1], seed)
>>
>>
>> if __name__ == "__main__":
>>     """
>>     se demuestra que la distribucion es plana,
>>     pero la PRUEBA matematica se la dejo a otro...
>>
>>     """
>>
>>     d = {}
>>     k, seed = randint_1_7()
>>
>>     for n in range(100000):
>>         k, seed = randint_1_7(seed)
>>         if k in d:
>>             d[k] += 1
>>         else:
>>             d[k] = 1
>>
>>     print(d)
>>
>>
>>
>>
>> On Tue, Jul 2, 2019 at 10:10 PM lasizoillo <lasizoillo en gmail.com> wrote:
>>
>>> Buenas,
>>>
>>> Lo primero sería acotar cual es realmente el problema. En una entrevista
>>> de trabajo alguien tiene que desentrañar si eres apto o no para un puesto y
>>> esa aptitud puede tener varias facetas:
>>> - Eres capaz de poner en duda los requisitos y plantear alternativas
>>> mejores para la empresa
>>> - Eres capaz de resolver problemas lógicos
>>> - Ante un problema que muy posiblemente no sabes por dónde cogerlo...
>>> ¿cómo vas a reaccionar? te enfadarás, tratarás de colar una solución
>>> erronea, asumirás que no sabes hacer eso pero plantearás estrategias para
>>> atacar el problema, ...
>>>
>>> Así que lo primero negociaría si realmente no se puede simplificar el
>>> enunciado porque lo que realmente se quiere evaluar el conocimiento técnico
>>> o recursos para atacar este problema. Si les vale ser capaz de poner en
>>> duda requisitos peregrinos eso que me ahorraría. Si quiere una solución
>>> técnica pasaría a atacar el problema, reconociendo que no sé la solución a
>>> priori, y pensaría en voz alta algunas cosas evidentes:
>>> - Una sola llamada a la función randint(1,5) no tiene información
>>> suficiente para hacer el equivalente a randint(1,7)
>>> - No puedo sumar 7 "tiradas" de randint(1,5) y dividir entre 5 porque la
>>> distribución no sería plana.
>>> - Al no ser una potencia de dos no puedo convertir a binario la función
>>> randint(1,5) y codificar los bits del número. Ejemplo 1 y 3 es un 0, 2 y 4
>>> es un 1 y 5 vuelvo a calcular. 2^3=8, por lo que tres bits de tiradas
>>> binarias me darían números del 0 al 7, no del 1 al 7.
>>>
>>> Ahora diría en alto lo que me parece una solución válida que me ha
>>> venido a la cabeza: lo mismo que con la función randint(1,5) desechaba
>>> cuando salía 5 para simular tiradas de cara o cruz, puedo eliminar cuando
>>> el resultado de calcular 3 bits me da un número que equivale a 0. Pensaría
>>> si cumple con las restricciones del enunciado (creo que si) y pasaría a una
>>> implementación rápida.
>>>
>>> def rand_0_1() -> int:
>>>      while True:
>>>           num = randint(1, 5)
>>>           if num==5:
>>>               continue
>>>           return num % 2
>>>
>>> def randint_1_7() -> int:
>>>      while True:
>>>           num = rand_0_1() * 4 + rand_0_1() * 2 + rand_0_1()
>>>           if num:
>>>              return num
>>>
>>> Le comentaría que lo suyo sería hacer una función de test para quedarme
>>> tranquilo con que el resultado es correcto y poder refactorizar en el
>>> futuro si se me ocurre una solución mejor. Escucharía si quiere dejarlo
>>> aquí o si quiere ver la función que haga el test (que no es trivial, pero
>>> tampoco demasiado complicada). Pero la función de test ya se escapa a tu
>>> propuesta ;-)
>>>
>>> Un saludo,
>>>
>>> Javi
>>>
>>>
>>> El mié., 3 jul. 2019 a las 1:50, Jose Caballero (<
>>> jcaballero.hep en gmail.com>) escribió:
>>>
>>>> Hola,
>>>>
>>>> a un colega le han preguntado durante una entrevista de trabajo lo
>>>> siguiente:
>>>> ¿cómo generar una distribución plana de enteros aleatorios, del 1 al 7,
>>>> usando únicamente random.randint(1,5)?
>>>> O sea, sin usar ninguna otra función que genere números aleatorios.
>>>>
>>>> Y he pensado en proponer el reto aquí, a ver lo que los miembros de la
>>>> lista sugieren.
>>>>
>>>> Un saludo,
>>>> Jose
>>>> _______________________________________________
>>>> Python-es mailing list
>>>> Python-es en python.org
>>>> https://mail.python.org/mailman/listinfo/python-es
>>>>
>>> _______________________________________________
>>> Python-es mailing list
>>> Python-es en python.org
>>> https://mail.python.org/mailman/listinfo/python-es
>>>
>> _______________________________________________
>> Python-es mailing list
>> Python-es en python.org
>> https://mail.python.org/mailman/listinfo/python-es
>>
> _______________________________________________
> Python-es mailing list
> Python-es en python.org
> https://mail.python.org/mailman/listinfo/python-es
>
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://mail.python.org/pipermail/python-es/attachments/20190704/8e822704/attachment.html>
------------ próxima parte ------------
A non-text attachment was scrubbed...
Name: hist_randint.png
Type: image/png
Size: 13680 bytes
Desc: no disponible
URL: <http://mail.python.org/pipermail/python-es/attachments/20190704/8e822704/attachment.png>


Más información sobre la lista de distribución Python-es