Si tuvieras la oportunidad de abrir todos los sobres para llenar el álbum de la Copa Mundial de la FIFA 2022, ¿cuántos necesitarías? Para descubrirlo vamos a hacer una simulación computacional en la que recrearemos cada sobre con 5 stickers y los pegaremos en el álbum hasta llenarlo. Lo haremos muchas veces hasta llegar a varias conclusiones.
He preparado un repositorio en GitHub con el código de este proyecto para que puedas clonarlo, e incluso mejorarlo.
Para seguir te recomiendo tener las bases de conocimiento en Python y estadística. Puedes tomar los siguientes cursos:
- Curso de Estadística Computacional con Python
- Curso de Estadística Inferencial para Data Science e Inteligencia Artificial
Conociendo nuestras variables: álbum y stickers
Lo primero que necesitamos es definir las variables que ingresarán a nuestro modelo matemático. En nuestro caso, según las especificaciones de Panini (el fabricante del álbum oficial del Mundial Qatar 2022), encontramos que:
- Para completar el álbum, tenemos que coleccionar 638 stickers diferentes.
- Hay otros 80 stickers adicionales que no forman parte de la colección principal. Así que no consideraremos a estos dentro de nuestro modelo.
- Cada paquete de cromos contiene 5 stickers dentro.
Puedes encontrar esta información sobre los stickers o datos sobre el álbum.
Creando el modelo matemático
Ya conocemos las variables que utilizaremos y es hora de crear el modelo. Primero te explicaré el proceso paso a paso y luego escribiremos el código en Python. Consideremos lo siguiente:
- Cada sticker está asignado aleatoriamente a cada paquete.
- El remuestreo se hace con reemplazo. De esta manera, podemos tener duplicados (esto ocurre en la vida real).
- Básicamente, tenemos un enfoque de bootstrapping.
Ahora lo que vamos a hacer es:
- Crear un álbum con 638 espacios por llenar.
- Generar un paquete con 5 stickers aleatorios entre 1 y 638.
- “Abrir” cada paquete y pegar los stickers en el álbum.
- Repetir este proceso hasta que se hayan llenado todos los espacios del álbum.
Este procedimiento lo podemos repetir una y otra vez. Te recomiendo hacerlo mínimo 1000 veces. El código se vería así:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
simul = 1000
amount = []
for i in range(1, simul+1):
stickers = (list(np.arange(1, 639)))
iterations = 0
while len(stickers) >0:
val_to_remove = np.random.randint(1, 639, size=5)
for val in val_to_remove:
if val in stickers:
stickers.remove(val)
iterations += 1
amount.append(iterations)
Como observas, tenemos la variable amount
que inicialmente fue declarada como un array vacío. Ahora iremos almacenando el número de iteraciones (stickers abiertos) necesarios hasta llenar el álbum. Como hicimos 1000 simulaciones, tenemos que graficar la distribución así:
fig, ax = plt.subplots(figsize=(12, 7))
plt.hist(amount, bins=30)
plt.title('Simulation of opening 1000 packages', size=16)
plt.xlabel('Packages')
plt.ylabel('Count')
plt.show()

Ya tenemos una idea más clara de cuántos sobres tenemos que abrir, pero exploremos este proceso con más profundidad. Para ello vamos a convertir nuestro array amount
en un data frame y obtendremos sus estadísticos descriptivos a partir de él.
amount_df = pd.DataFrame(amount)
print(amount_df.describe())
Esto nos da como resultado:
count 1000.000000
mean 902.181000
std 163.262828
min 572.000000
25% 792.000000
50% 873.000000
75% 984.250000
max 1693.000000
También podemos obtener un intervalo de confianza. Generalmente, se usa el 95%.
ci_2_5, ci_97_5 = np.percentile(amount, [2.5, 97.5])
print(f'CI 95%: {ci_2_5}, {ci_97_5}')
Y así obtenemos:
CI 95%: 659.975, 1307.2999999999997
¿Cuántos paquetes necesitas abrir?
Dado que estamos involucrando aleatoriedad, hablamos de un proceso estocástico. No podemos decir exactamente un número X de paquetes a abrir. Por lo tanto, conviene mejor hablar de un rango de valores.
Con base en los resultados obtenidos, podemos decir que:
- Tenemos una probabilidad del 95% de que el número de paquetes a abrir esté entre 660 y 1307.
- Existe una probabilidad del 50% de que nos tome 873 paquetes completar el álbum.
Todo esto lo podemos visualizar mejor en una curva de probabilidad acumulada. Para hacerlo tenemos que crear una función.
defecdf(data):
"""Compute ECDF for a one-dimensional array of measurements."""
# Number of data points: n
n = len(data)
# x-data for the ECDF: x
x = np.sort(data)
# y-data for the ECDF: y
y = np.arange(1, n+1) / n
return x, y
Ahora calculamos y graficamos:
x_norm, y_norm = ecdf(amount)
#Plot
fig, ax = plt.subplots(figsize=(12, 7))
plt.plot(x_norm, y_norm)
plt.title('ECDF of 1000 opened packages', size=16)
plt.xlabel('Opened packages')
plt.ylabel('Cumulative probability')
plt.show()

Con esta curva podemos visualizar mejor las probabilidades de llenar el álbum con X cantidad de paquetes. Por ejemplo, al abrir el paquete 1108, ya tendremos una probabilidad del 90%.
¡Tu turno! Busca la manera de optimizar este proceso
El enfoque que le hemos dado aquí es abrir tantos paquetes como podamos hasta completar el álbum del Mundial Qatar 2022. Pero normalmente, como coleccionistas, solemos intercambiar figuritas y/o comprarlas de forma individual, aunque esto resulte más costoso.
Ahora me gustaría preguntarte, ¿cuál crees que sería la forma óptima de completar el álbum? ¿Existe un punto en el que conviene dejar de comprar paquetes e ir a comprar las figuritas de forma individual? ¿Cómo modelarías este proceso? Te leo en los comentarios.
Curso para Crear tus Proyectos de Ciencia de Datos