Saltar al contenido

Números aleatorios en Python con NumPy y SciPy

Introducción

En este artículo vamos a hacer un repaso de algunos métodos que tenemos para generar números aleatorios en Python. Los números aleatorios son importantísimos en computación: aquí en Pybonacci ya los hemos aplicado en nuestra simulación de Monte Carlo para calcular áreas de polígonos y en nuestro artículo sobre algoritmos heurísticos en Python. Como veremos, NumPy ofrece funciones para generar datos aleatorios simples y algunas distribuciones estadísticas, que luego amplía SciPy.

Vamos a mencionar sin explicar las distribuciones uniforme y normal, así que si quieres una explicación más detallada te recomiendo que leas nuestro artículo sobre estadística en Python con SciPy. Haremos referencia a él más adelante.
En esta entrada se han usado python 3.3.0, numpy 1.7.0rc1 y scipy 0.11.0.

¿Aleatorios?

Antes que nada, hay algo importante que tenemos que aclarar. En realidad, no hay algoritmos que generen números puramente aleatorios y que sean deterministas, por lo que usando solamente software es imposible obtener números verdaderamente aleatorios. Como dicen en Ask SciPy, para generar números aleatorios con un ordenador necesitas muestrear algún proceso físico real: por ejemplo, en www.random.org utilizan ruido atmosférico, y en www.fourmilab.ch/hotbits/ desintegración radiactiva.

En computación realmente se dispone de números pseudoaleatorios, que son secuencias determinadas a partir de unos ciertos datos iniciales que se parecen bastante a una aleatoria. NumPy utiliza un algoritmo llamado “Mersenne twister“, creado por dos matemáticos japoneses y que utilizan otros programas como MATLAB.

Ahora que ya hemos hecho esta aclaración, en adelante llamaremos aleatorios a los números pseudoaleatorios – por brevedad 🙂

En la librería estándar de Python viene ya incluido el módulo random, con funciones pensadas para trabajar con valores escalares y listas. Las que vamos a ver ahora pueden trabajar con arrays de NumPy.

Nota: Algunas de estas funciones tenían (o tienen) una documentación un poco deficiente pero afortunadamente están recibiendo algo del amor que necesitan. Voy a enlazar a la versión de desarrollo de la referencia, que es la que ha incorporado esos cambios, y lo dejaré así hasta que salga NumPy 1.7.0 final.

Datos aleatorios simples con NumPy

Generación de datos aleatorios

En el paquete random de NumPy encontramos varias funciones para generar datos aleatorios de manera sencilla. La primera es np.random.rand, que devuelve un número aleatorio procedente de una distribución uniforme en el intervalo \([0, 1)\). Admite como argumentos opcionales la forma del array de salida:

La función np.random.random_sample hace lo mismo, pero recibe el argumento en forma de tupla. Tiene cuatro alias: random, sample y ranf.

Antes de seguir, ¿recordáis que hemos dicho que estos números son pseudoaleatorios? A veces nos puede interesar, por ejemplo para pruebas, utilizar siempre una misma secuencia pseudoaleatoria. Utilizando la función np.random.seed imponemos las condiciones iniciales del generador; si no se llama (como hemos hecho antes), NumPy escoge la hora como semilla, de tal forma que cada programa utilice secuencias diferentes:

Si queremos generar datos enteros entonces tenemos que usar la función np.random.randint, que admite un argumento obligatorio y dos opcionales:

  • Si se llama con un argumento, np.random.randint(a) devuelve una muestra de la distribución uniforme discreta en \([0, a)\).
  • Si se llama con dos argumentos, np.random.randint(a, b) devuelve una muestra de la distribución uniforme discreta en \([a, b)\).
  • Si se llama con tres argumentos, np.random.randint(a, b, size) devuelve un array de muestras en \([a, b)\) y de tamaño size.

Mezclas y elecciones aleatorias

NumPy también nos permite, dado un array de datos ya existente, mezclarlo de manera aleatoria (como barajar un mazo de cartas) o escoger un elemento al azar.

La función np.random.choice (nueva en NumPy 1.7.0) recibe cuatro argumentos (uno obligatorio y tres opcionales) que dan bastante juego:

  • El argumento a es o bien el array del que vamos a extraer los elementos o un entero. En este último caso se utiliza np.arange(a).
  • El argumento size es un entero o tupla de enteros y es el tamaño del array de salida. Por defecto es None (y no 1 como indica la cadena de documentación de la función), y en este caso se devuelve un escalar.
  • El argumento replace es un valor booleano que indica si se toma la muestra con reposición o sin ella, esto es, si se pueden repetir los elementos o no. Si se escoge muestra sin reposición, evidentemente la salida no puede tener más elementos que el array de partida. Por defecto se toma con reposición (True)
  • El argumento p es una lista de las probabilidades asociadas a cada elemento. Por defecto se asume que todos tienen la misma probabilidad de aparecer.

Vamos a ver algunos ejemplos:

Por último en este apartado tenemos dos funciones que reordenan de manera aleatoria los elementos de un array: shuffle y permutation. La primera lo hace in situ, y la segunda devuelve el array desordenado:

Distribuciones estadísticas

Hasta ahora hemos manejado básicamente distribuciones uniformes, pero NumPy incluye otras distribuciones estadísticas continuas y SciPy amplía con muchas más, añadiendo también distribuciones discretas. Estas se encuentran en el paquete scipy.stats. Usando las distribuciones de NumPy:

Date cuenta de que se proporciona la función randn como atajo a la normal estándar, por ser enormemente común.

Si se utiliza SciPy, hay que llamar a la función rvs de la distribución:

Si quieres más información o utilizar el resto de funciones estadísticas que ofrece SciPy, puedes leer nuestro artículo sobre estadística en Python con SciPy.

Ahora ya puedes hacer sorteos de lotería, bonitas simulaciones de Monte Carlo o explorar juegos de azar con Python. Y tú, ¿para qué utilizarías números aleatorios?

7 comentarios en «Números aleatorios en Python con NumPy y SciPy»

    1. ¡Gracias a ti! 🙂 Pues como proyecto es muy interesante, la parte de ajustar la distribución es muy fácil con SciPy:
      http://glowingpython.blogspot.it/2012/07/distribution-fitting-with-scipy.html (en inglés)
      Y en cuanto a la interfaz gráfica no sería nada difícil de hacer, he visto el vídeo que has enlazado y es bastante simple. matplotlib está programado de tal manera que es muy fácil incrustarlo en aplicaciones gráficas hechas con todo tipo de bibliotecas (PyQt, PyGTK, …)
      http://eli.thegreenplace.net/2009/01/20/matplotlib-with-pyqt-guis/
      No tengo ni idea de ninguna de las dos cosas anteriores, pero en cualquier caso si te podemos ayudar en algo ya sabes dónde estamos 🙂
      Sí que hay algoritmos que generen números puramente aleatorios y que *no* sean deterministas, por tanto creo que la frase está bien construida 😛
      ¡Un saludo!

  1. alguien ayudeme con este problema
    Estas en Las Vegas jugando dados, necesitas un 7 ó un 11. Crea un simulador que te diga si al tirar los
    dados obtendrías alguno de estos números.
    El programa no solicita ningún dato al usuario, únicamente genera una salida que indica el número
    obtenido por cada dado y si la tirada sería ganadora o no.
    Ejemplo (Salida del programa en negro, entrada del programa en verde):
    *******************************************************
    ¡Tiraste los dados: 5, 6!
    *******************************************************
    Sacaste 11. ¡Ganaste!
    *******************************************************
    Reglas/restricciones:
    *Reglas y restricciones a respetar para que el programa sea considerado como entregado. Debes de crear
    una función que utilizando el módulo random (especificamene la función randint) simule una tirada de 2
    dados. Imprime el resultado del tiro en pantalla. Si la suma de las cantidades obtenidas en los dados es 7
    u 11 imprime ¡Ganaste!, de lo contario imprime ¡Perdiste!
    En tu programa principal únicamente debe de estar la ejecución de la función, y es esta la que debe de
    hacer todo el procesamiento necesario e imprimir en pantalla.

  2. Muchas gracias por campartir tu conocimiento !
    Soy programadora front-end, estaba desarrollando una librería estadística en JS ….y llegué hasta aquí y ahora soy fan de python y scipy.
    genial!

Responder a Eduardo Hurtado Dominguez Cancelar la respuesta

Tu dirección de correo electrónico no será publicada.

seventy five − 72 =

Pybonacci