Muchos programas necesitan valores aleatorios (aparentemente) para simular sucesos del mundo real.
Entre los ejemplos más comunes y conocidos se incluyen:
('Heads', 'Tails').Generar valores verdaderamente aleatorios con un ordenador es un desafío técnico sorprendentemente difícil, por lo que es posible que veas estos resultados referidos como «pseudoaleatorios».
En la práctica, una biblioteca bien diseñada como el módulo random de la biblioteca estándar de Python es rápida, flexible y ofrece resultados que son más que suficientes para la mayoría de las aplicaciones de modelado, simulación y juegos.
El resto de esta página enumera algunas de las funciones más comunes de random.
Te animamos a explorar la documentación completa de random, ya que hay muchas más opciones que las que cubrimos aquí.
El módulo random NO debe usarse para aplicaciones de seguridad o criptográficas.
En su lugar, Python proporciona el módulo secrets.
Está especialmente optimizado para la seguridad criptográfica.
Algunos de los problemas previos y las razones para crear el módulo secrets se pueden encontrar en PEP 506.
Antes de poder utilizar las herramientas del módulo random, primero debes importarlo:
>>> import random
# Choose random integer from a range
>>> random.randrange(1000)
360
>>> random.randrange(-1, 500)
228
>>> random.randrange(-10, 11, 2)
-8
# Choose random integer between two values (inclusive)
>>> random.randint(5, 25)
22
Para evitar escribir el nombre del módulo, puedes importar funciones específicas por su nombre:
>>> from random import choice, choices
# Using choice() to pick Heads or Tails 10 times
>>> tosses = []
... for side in range(10):
... tosses.append(choice(['H', 'T']))
>>> print(tosses)
['H', 'H', 'H', 'H', 'H', 'H', 'H', 'T', 'T', 'H']
# Using choices() to pick Heads or Tails 8 times
>>> picks = []
... picks.extend(choices(['H', 'T'], k=8))
... print(picks)
['T', 'H', 'H', 'T', 'H', 'H', 'T', 'T']
La función randrange() tiene tres formas, para seleccionar un valor aleatorio de range(start, stop, step):
randrange(stop) devuelve un número entero n tal que 0 <= n < stop
randrange(start, stop) devuelve un número entero n tal que start <= n < stop
randrange(start, stop, step) devuelve un número entero n tal que start <= n < stop y n está en la secuencia start, start + step, start + 2*step...
Para el caso habitual en el que step == 1, la función randint(a, b) puede ser más cómoda y legible.
Los resultados posibles de randint() incluyen el límite superior, por lo que randint(a, b) es lo mismo que usar randrange(a, b+1):
>>> import random
# Select one number at random from the range 0, 499
>>> random.randrange(500)
219
# Select 10 numbers at random between 0 and 9 two steps apart.
>>> numbers = []
... for integer in range(10):
... numbers.append(random.randrange(0, 10, 2))
>>> print(numbers)
[2, 8, 4, 0, 4, 2, 6, 6, 8, 8]
# roll a die
>>> random.randint(1, 6)
4
Las funciones de esta sección suponen que partes de alguna secuencia u otro contenedor.
Normalmente será una list o, con algunas limitaciones, una tuple o un set (una tuple es inmutable y un set no tiene orden).
choice() y choices()
La función choice() devuelve un elemento elegido al azar de una secuencia dada.
En su forma más simple, esto podría ser el lanzamiento de una moneda:
# This will pick one of the two values in the list at random 5 separate times
>>> [random.choice(['H', 'T']) for _ in range(5)]
['T', 'H', 'H', 'T', 'H']
Podríamos conseguir esencialmente lo mismo usando la función choices(), proporcionando un argumento de palabra clave con la longitud de la lista:
>>> random.choices(['H', 'T'], k=5)
['T', 'H', 'T', 'H', 'H']
En los ejemplos anteriores, supusimos una moneda justa con la misma probabilidad de cara o cruz, pero también se pueden especificar pesos. Por ejemplo, si una bolsa contiene 10 bolas rojas y 15 bolas verdes y queremos sacar una al azar:
>>> random.choices(['red', 'green'], [10, 15])
['red']
sample()El ejemplo de choices() anterior supone lo que los estadísticos llaman «muestreo con reemplazo».
Cada elección no tiene ningún efecto sobre la probabilidad de elecciones futuras, y la distribución de las posibles elecciones se mantiene igual de una elección a otra.
En el ejemplo de las bolas rojas y verdes: después de cada elección, devolvemos la bola a la bolsa y la agitamos bien antes de la siguiente elección. Esto contrasta con una situación en la que sacamos una bola roja y esta se queda fuera. No devolver la bola significa que ahora hay menos bolas rojas en la bolsa, y la siguiente elección tiene ahora menos probabilidad de ser roja.
Para simular este «muestreo sin reemplazo», el módulo random proporciona la función sample().
La sintaxis de sample() es similar a la de choices(), salvo que añade un parámetro de palabra clave counts:
>>> random.sample(['red', 'green'], counts=[10, 15], k=10)
['green', 'green', 'green', 'green', 'green', 'red', 'red', 'red', 'red', 'green']
Las muestras se devuelven en el orden en que se eligieron.
shuffle()Tanto choices() como sample() devuelven nuevas listas cuando k > 1.
En cambio, shuffle() aleatoriza el orden de una lista in place, y el orden original se pierde:
>>> my_list = [1, 2, 3, 4, 5]
>>> random.shuffle(my_list)
>>> my_list
[4, 1, 5, 2, 3]
Hasta ahora nos hemos centrado en casos en los que todos los resultados son igual de probables.
Por ejemplo, random.randrange(100) tiene la misma probabilidad de dar cualquier número entero del 0 al 99.
Muchas situaciones del mundo real son mucho menos simples que esto.
Como resultado, los estadísticos han creado una amplia variedad de distributions para describir matemáticamente los resultados del «mundo real».
Para los números enteros, randrange() y randint() se usan cuando todas las probabilidades son iguales.
Esto se llama distribución uniform.
Existen equivalentes de coma flotante para randrange() y randint().
random() devuelve un valor float x tal que 0.0 <= x < 1.0.
uniform(a, b) devuelve x tal que a <= x <= b.
>>> [round(random.random(), 3) for _ in range(5)]
[0.876, 0.084, 0.483, 0.22, 0.863]
>>> [round(random.uniform(2, 5), 3) for _ in range(5)]
[2.798, 2.539, 3.779, 3.363, 4.33]
También llamada distribución «normal» o curva «en forma de campana», es una forma muy común de describir la imprecisión en los valores medidos.
Por ejemplo, supón que la fábrica en la que trabajas acaba de comprar 10.000 tornillos que deberían ser idénticos.
Quieres configurar el robot de la fábrica para que los manipule, así que pesas una muestra de 100 y descubres que tienen un peso medio (o mean) de 4,731 g.
Es muy poco probable que esto signifique que todos pesan exactamente 4,731 g.
Puede que descubras que los valores van de 4,627 a 4,794 g, pero se agrupan en torno a 4,731 g.
Esta es la Gaussian distribution, en la que las probabilidades alcanzan su máximo en la media y disminuyen de forma simétrica a ambos lados (de ahí la «forma de campana»).
Para simular esto en software, necesitamos alguna forma de especificar la anchura de la curva (normalmente, los tornillos caros se agruparán más estrechamente en torno a la media que los baratos).
Por convención, esto se hace con la standard deviation: valores pequeños para una curva pronunciada y estrecha, grandes para una curva baja y ancha.
A los matemáticos les encantan las letras griegas, así que usamos μ («mu») para representar la media y σ («sigma») para representar la desviación típica.
Así, si lees que «el 95 % de los valores están dentro de 2σ de μ» o que «el bosón de Higgs se ha detectado con una confianza de 5 sigma», esos comentarios se refieren a la desviación típica.
>>> mu = 4.731
>>> sigma = 0.316
>>> [round(random.gauss(mu, sigma), 3) for _ in range(5)]
[4.72, 4.957, 4.64, 4.556, 4.968]