Ir al contenido
wannacode

Intervalos de confianza

En resumen: Un intervalo de confianza es un rango alrededor del valor de una muestra que, al 95 %, atrapa el valor verdadero en unas 95 de cada 100 muestras; el bootstrap lo construye con remuestras con reemplazo.

Problema

«¿Cuánto gasta un cliente por pedido?»

El jefe pregunta cuál es el pedido medio. En la vida real rara vez lo tienes todo: digamos que tienes 200 pedidos sacados al azar del año. Aquí tenemos también el año entero, 10 459 pedidos sin los cancelados, y podemos ver qué pasa:

Pythondatos: las tablas de la tienda

Tres muestras de 200 dan tres medias distintas: 9,77 €, 10,74 € y 11,16 €. Sabes por la lección sobre muestras que la media tiene ruido. Pero solo tienes una muestra. ¿Qué le dices al jefe: un número o algo más?

Es más honesto decir «la media está en algún punto entre … y …». Falta averiguar cuán ancho debe ser ese «algún punto», a partir de la muestra que tienes y nada más.

La idea

La muestra en lugar del año: el bootstrap

Si pudieras sacar muestras nuevas del año, verías cuánto oscila la media. No puedes. Así que usas la muestra como un pequeño modelo del año: sacas de ella 200 pedidos con reemplazo y calculas la media. Eso es una remuestra. Un pedido sale dos veces, otro ninguna, y la media es un poco distinta cada vez.

Lo haces 10 000 veces y miras dónde están las medias. Cortas el 2,5 % de las más pequeñas y el 2,5 % de las más grandes. El 95 % central es el intervalo de confianza. El método se llama bootstrap:

Pythondatos: las tablas de la tienda

Los primeros 8 pedidos de la muestra van de 0,90 € a 45,20 €. Las tres primeras remuestras dan medias de 10,07 €, 11,07 € y 11,13 €. La media de la muestra es 11,41 €, y el intervalo del 95 % va de 10,04 € a 12,83 €. La media verdadera del año es 10,63 €: está dentro.

rng.choice(sample, size=(10_000, 200)) es una tabla de 10 000 × 200: cada fila es una remuestra. mean(axis=1) da una media por fila. No hace falta ningún bucle.

Míralo

Cómo nace un intervalo de una muestra

El mismo código, despacio: se copian fichas de la muestra a una remuestra, su media cae sobre el eje y 10 000 medias así forman un montón.

import numpy as np
import pandas as pd
orders = pd.read_csv('year_orders.csv')
items = pd.read_csv('year_items.csv')
cancelled = orders.loc[orders['status'] == 'cancelled', 'id']
items = items[~items['order_id'].isin(cancelled)]
items['revenue'] = items['quantity'] * items['unit_price']
totals = items.groupby('order_id')['revenue'].sum()
rng = np.random.default_rng(42)
sample = rng.choice(totals.to_numpy(), size=200, replace=False)
print(sample[:8])
boots = rng.choice(sample, size=(10_000, 200)).mean(axis=1)
print(boots[:3].round(2))
low, high = np.quantile(boots, [0.025, 0.975])
print(round(sample.mean(), 2), round(low, 2), round(high, 2))
print(round(totals.mean(), 2))
Paso a paso, en palabras
  1. totals es el valor de cada pedido del año. En la vida real no ves todo: solo tienes una muestra.
  2. sample es una muestra de 200 pedidos. Arriba están los primeros 8, en euros: 3,6, 0,9, 2,1, 17, 45,2, 13,2, 3,4 y 2.
  3. Una remuestra: 200 extracciones de sample con reemplazo. Un pedido sale dos veces, otro ninguna.
  4. La media de la remuestra cae como un punto sobre el eje. Las tres primeras son 10,07 €, 11,07 € y 11,13 €.
  5. Así 10 000 veces. Los puntos se amontonan alrededor de la media de la muestra, 11,41 €.
  6. Se corta el 2,5 % de la izquierda y el 2,5 % de la derecha. El 95 % central es el intervalo: de 10,04 € a 12,83 €.
  7. La media verdadera del año es 10,63 €, y está dentro. En la vida real no la conoces: el intervalo dice cuánto puede equivocarse la estimación.

El montón de la escena es un boceto: los números de los rótulos son reales, desde la muestra hasta los límites del intervalo. Aquí están las 10 000 medias reales con matplotlib, con los dos límites (líneas azules) y la media verdadera (la discontinua naranja):

Pythondatos: las tablas de la tienda

Pruébalo

¿Sin reemplazo?

1. En el bootstrap cada remuestra saca 200 pedidos de una muestra de 200. ¿Qué pasa si sacas sin reemplazo?

La mediana de los pedidos es más robusta frente a los pedidos grandes. Haz un intervalo del 95 % para la mediana con la misma muestra de 200: guarda en meds las medianas de 10 000 remuestras, y en low y high los límites del intervalo.

Pythondatos: las tablas de la tienda

La idea

Qué significa el 95 %

La media verdadera del año es un número: 10,63 €. El intervalo de una muestra o la atrapa o no. El 95 % es una promesa del método: si sacas muchas muestras y construyes un intervalo para cada una, unos 95 de cada 100 intervalos atraparán la verdad. Esto se llama nivel de confianza.

Aquí tenemos el año entero y podemos comprobar la promesa. 100 muestras de 200, para cada una un bootstrap con 1000 remuestras:

Pythondatos: las tablas de la tienda

93 de 100 intervalos atrapan 10,63 €. Eso está cerca de 95: las 100 muestras son aleatorias ellas mismas, y las siguientes 100 darán algo algo distinto. Unos 5 de cada 100 intervalos honestos no atrapan la verdad, y no hay forma de saber cuáles.

Más precisamente, para curiosos

Es tentador decir «con una probabilidad del 95 % la media verdadera está entre 10,04 € y 12,83 €». Estrictamente, no es así: la media verdadera no es aleatoria, y el intervalo de tu muestra la contiene o no. Lo aleatorio es la muestra. Así que el 95 % habla del método, no de un número concreto. En un informe escribe «intervalo de confianza del 95 %: 10,04 €–12,83 €».

El bootstrap funciona cuando la muestra es aleatoria. Si los 200 pedidos son de un solo diciembre, el intervalo será para diciembre, por muchas remuestras que hagas: las remuestras no arreglan una muestra sesgada.

1. El intervalo para el pedido medio va de 10,04 € a 12,83 €. ¿Qué frase es verdadera?

La idea

La fórmula como atajo

Para una media hay un atajo sin 10 000 remuestras. El ruido de la media es el error estándar: std / √n. Con una distribución normal el 95 % central queda a menos de 1,96 errores estándar del centro. Así que el intervalo es la media ± 1,96 × std / √n:

Pythondatos: las tablas de la tienda

El error estándar es 0,72 €, y el intervalo va de 10,00 € a 12,81 €. El bootstrap dio 10,04 €–12,83 €: casi lo mismo. La segunda línea comprueba la promesa de la fórmula: de 1000 muestras de 200, 948 intervalos atrapan la verdad. Cerca de 950.

std(ddof=1) divide entre n − 1 en lugar de entre n, como std() en pandas. Con 200 pedidos la diferencia está en la tercera cifra.

Más precisamente, para curiosos

El número 1,96 viene de la distribución normal: el 95 % del área queda entre −1,96 y 1,96 desviaciones estándar. La media de 200 pedidos es casi normal incluso cuando los propios pedidos tienen una cola larga (el teorema central del límite de la lección sobre muestras). Con muestras pequeñas, de menos de 30, o con una cola muy larga la fórmula se aleja más, y el bootstrap es más honesto.

La idea

Un intervalo para una proporción

¿Qué parte de los pedidos está cancelada? Una proporción es una media de ceros y unos: True es 1, False es 0, y mean() da la proporción. Así que el bootstrap y la fórmula funcionan también aquí. La fórmula para una proporción es p ± 1,96 × √(p(1 − p) / n):

Pythondatos: las tablas de la tienda

En una muestra de 500 pedidos el 5,8 % está cancelado. El bootstrap da del 3,8 al 8,0 %, y la fórmula del 3,8 al 7,8 %. La proporción verdadera del año es del 5,9 %. Con 500 pedidos conoces la proporción con unos ± 2 puntos: «5,8 %» sin intervalo suena más preciso de lo que es.

La idea

Una muestra pequeña, un intervalo ancho

Cuantos menos pedidos, más ruido tiene la media y más ancho es el intervalo:

Pythondatos: las tablas de la tienda

50 pedidos dan un intervalo de 4,73 € de ancho, 200 pedidos 2,69 € y 800 pedidos 1,35 €. 4 veces más datos dan un intervalo de más o menos la mitad de ancho, porque el error estándar baja con la raíz cuadrada de n. La precisión es cara: reducir el ancho a la mitad otra vez necesita otra vez 4 veces más pedidos.

Ejercicio

La respuesta para el jefe

Una muestra nueva de 400 pedidos (semilla 2026). Haz un intervalo del 95 % para el pedido medio de dos maneras: con un bootstrap de 10 000 remuestras (boot_low, boot_high) y con la fórmula (se es el error estándar, f_low y f_high son los límites).

Pythondatos: las tablas de la tienda

El jefe está pensando en envío gratis a partir de 20 €. ¿Qué parte de los pedidos supera los 20 €? Con una muestra de 300 pedidos (semilla 7) guarda la proporción en p y su intervalo del 95 % en low y high.

Pythondatos: las tablas de la tienda

Test

Ponte a prueba

1. ¿Por qué el bootstrap toma los cuantiles 0,025 y 0,975 de las medias y no 0,05 y 0,95?
2. El intervalo de 200 pedidos tiene 2,69 € de ancho. ¿Cuántos pedidos necesitas para un intervalo de unos 1,35 € de ancho?
3. La fórmula es la media ± 1,96 × std / √n. ¿Cuándo prefieres el bootstrap?
4. En una muestra de 500 pedidos el 5,8 % está cancelado, y el intervalo va del 3,8 al 7,8 %. El jefe dice: «Así que las cancelaciones son el 5,8 %.» ¿Qué respondes?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·