De 12 000 filas a una distribución
Lo que vamos a construir hoy
Apertura
12 000 filas no se leen: se cuentan.
Dos horas en cuatro momentos
La primera pregunta de la gerencia era cuánto tarda un pedido típico. Antes de responderla con un número, hay que ver cómo se reparten los tiempos.
Dos ideas de la sesión 1, con más precisión
El estrato no se promedia
No porque 3,3 «no exista», sino porque nada garantiza que del estrato 1 al 2 haya la misma distancia que del 5 al 6: los números son etiquetas con orden.
La lluvia viene con la ciudad
Con lluvia, los pedidos tardaron 7,8 min más; pero llueve más en Bogotá, donde los pedidos ya tardan más. Hoy lo vemos con una tabla cruzada.
Otra persona del curso revisa tus dos preguntas con tres criterios
| Criterio | Pregunta |
|---|---|
| Pertinencia | ¿La tabla de pedidos la puede responder? |
| Variables | ¿Qué columnas usa y de qué tipo son? |
| Alcance | ¿Basta con describir los 12 000 pedidos o hay que inferir? |
Distribuciones de frecuencias
¿Qué valores toma una variable y cuántas veces aparece cada uno? Esa es su distribución.
Una distribución dice qué valores aparecen y cuántas veces
La lista de los valores, categorías o intervalos que toma una variable, con cuántas veces aparece cada uno. Su forma más simple es una tabla de frecuencias.
- Las 12 000 filas de
categoriacaben en una tabla de 5 filas - La tabla no pierde nada de lo que importa para preguntar cuántos de cada uno
Cuatro columnas responden cuatro preguntas distintas
| Columna | Símbolo | Responde | Calificación de 4 estrellas |
|---|---|---|---|
| Frecuencia absoluta | \(n_i\) | ¿Cuántos? | 2959 pedidos |
| Frecuencia relativa | \(f_i\) | ¿Qué parte del total? | 41,7 % |
| Absoluta acumulada | \(N_i\) | ¿Cuántos hasta aquí? | 4445 pedidos |
| Relativa acumulada | \(F_i\) | ¿Qué parte hasta aquí? | 62,6 % |
Sobre los 7099 pedidos calificados: «hasta aquí» quiere decir «de 1 a 4 estrellas».
Las relativas dividen entre el total; las acumuladas suman hasta la categoría
$$ \begin{aligned} f_i &= \frac{n_i}{n} && \text{relativa} \\[6pt] N_i &= n_1 + n_2 + \cdots + n_i && \text{absoluta acumulada} \\[6pt] F_i &= \frac{N_i}{n} && \text{relativa acumulada} \end{aligned} $$
\(n\) es el total de datos e \(i\) numera las categorías en su orden. Las \(n_i\) suman \(n\), y las \(f_i\) suman 1 (el 100 %).
Acumular exige un orden
«Hasta aquí» necesita un antes y un después: se acumulan las ordinales y las cuantitativas, nunca las nominales.
Variables cualitativas
En una nominal, el orden de la tabla lo eliges tú; en una ordinal, ya viene dado.
La tabla de una nominal: conteo y porcentaje
conteo = pedidos["categoria"].value_counts()
porcentaje = pedidos["categoria"].value_counts(normalize=True) * 100
tabla = pd.DataFrame({"pedidos": conteo, "%": porcentaje.round(1)})
tabla
#> pedidos %
#> categoria
#> Restaurante 7411 61.8
#> Mercado 1859 15.5
#> Farmacia 1415 11.8
#> Mascotas 794 6.6
#> Floristería 521 4.3value_counts(): las \(n_i\), de mayor a menornormalize=True: las \(f_i\); por 100, en %- La moda es la categoría más frecuente: Restaurante
En una nominal, las barras van de mayor a menor
- Barras separadas: son categorías, no un continuo
- El eje empieza en cero: la longitud es la cantidad
- Sin orden natural, se ordenan por tamaño
¿Torta o barras?
Para comparar las cinco categorías de comercio de Tingua, ¿qué gráfico conviene?
Barras. Comparar longitudes sobre un mismo eje es más preciso que comparar ángulos o áreas: Mercado (15,5 %) y Farmacia (11,8 %) se distinguen al instante en barras y cuesta más en una torta. La torta solo sirve para mostrar una parte contra el todo, con dos o tres porciones.
En una ordinal, la tabla va en el orden de la escala
# sort=False: en el orden de la escala (1 a 5), no por tamaño
estrellas = pedidos["calificacion"].value_counts(sort=False)
n = estrellas.sum() # solo los pedidos calificados
tabla = pd.DataFrame({
"pedidos": estrellas,
"%": (estrellas / n * 100).round(1),
"% acumulado": (estrellas.cumsum() / n * 100).round(1),
})
tabla
#> pedidos % % acumulado
#> calificacion
#> 1 72 1.0 1.0
#> 2 240 3.4 4.4
#> 3 1174 16.5 20.9
#> 4 2959 41.7 62.6
#> 5 2654 37.4 100.0sort=False: de 1 a 5, no por tamañocumsum(): suma hasta cada fila- El 20,9 % de las calificaciones es de 3 estrellas o menos
«El 37,4 % de los pedidos tiene 5 estrellas»: ¿es cierto?
Mira la tabla anterior: ¿sobre qué total se calculó ese 37,4 %?
No. Es el 37,4 % de los pedidos calificados. Sobre todos los pedidos es el 22,1 %, porque el 40,8 % no tiene calificación.
todas = pedidos["calificacion"].value_counts(
normalize=True, sort=False, dropna=False)
(todas * 100).round(1)
#> calificacion
#> 1 0.6
#> 2 2.0
#> 3 9.8
#> 4 24.7
#> 5 22.1
#> NaN 40.8
#> Name: proportion, dtype: float64La acumulada encuentra la mitad de los datos
| Estrellas | % acumulado |
|---|---|
| 3 o menos | 20,9 % |
| 4 o menos | 62,6 % |
- La acumulada llega al 50 % en las 4 estrellas: es la calificación mediana
- La satisfacción se resume con la mediana o con una proporción: el 79,1 % de los pedidos calificados tiene 4 o 5 estrellas
En una ordinal, las barras van en el orden de la escala
- Por tamaño quedarían Almuerzo, Noche, Tarde, Mañana: se perdería el recorrido del día
- En su orden se ven dos picos: el almuerzo y la noche
Variables cuantitativas
Un tiempo toma cientos de valores distintos: una fila por valor no resume nada.
Una discreta se tabula valor por valor, y su cola se agrupa
productos = pedidos["n_productos"].value_counts().sort_index()
print("Valores distintos:", len(productos),
"· del", productos.index.min(), "al", productos.index.max())
productos.head(6)
#> Valores distintos: 32 · del 1 al 44
#> n_productos
#> 1 3306
#> 2 3533
#> 3 2186
#> 4 980
#> 5 543
#> 6 370
#> Name: count, dtype: int64sort_index(): en el orden de los valores, no por tamaño- El 83,4 % de los pedidos lleva de 1 a 4 productos
- La cola llega a 44: en una tabla se agrupa como «10 o más»
Una continua tiene demasiados valores distintos para tabularlos uno a uno
tiempo = pedidos["tiempo_entrega_min"]
print("Valores distintos:", tiempo.nunique(), "de", len(tiempo))
print("Del", tiempo.min(), "al", tiempo.max(), "minutos")
#> Valores distintos: 649 de 12000
#> Del 6.0 al 200.9 minutos- Una fila por valor serían 649 filas: no resume nada
- Se agrupa en intervalos (clases) que no se traslapan y cubren todos los datos
La regla de Sturges da un punto de partida para el número de intervalos
$$ \begin{aligned} k &\approx 1 + \log_2 n && \text{número de intervalos} \\[6pt] c &\approx \frac{\text{máximo} - \text{mínimo}}{k} && \text{amplitud de cada uno} \end{aligned} $$
Con \(n = 12\,000\): \(k \approx 14{,}6\), unas 15 clases, de \(c \approx 13{,}4\) min. Es una guía, no una ley: para la tabla preferimos una amplitud redonda, 10 min, y una última clase abierta para la cola.
Con intervalos de 10 minutos, 649 valores caben en 9 filas
cortes = [0, 10, 20, 30, 40, 50, 60, 70, 80, float("inf")]
clases = pd.cut(tiempo, bins=cortes, right=False) # [a, b)
tabla = clases.value_counts(sort=False).to_frame("pedidos")
tabla["%"] = (tabla["pedidos"] / len(tiempo) * 100).round(1)
acumulado = tabla["pedidos"].cumsum() / len(tiempo) * 100
tabla["% acumulado"] = acumulado.round(1)
tabla
#> pedidos % % acumulado
#> tiempo_entrega_min
#> [0.0, 10.0) 8 0.1 0.1
#> [10.0, 20.0) 563 4.7 4.8
#> [20.0, 30.0) 3418 28.5 33.2
#> [30.0, 40.0) 4835 40.3 73.5
#> [40.0, 50.0) 2330 19.4 93.0
#> [50.0, 60.0) 627 5.2 98.2
#> [60.0, 70.0) 133 1.1 99.3
#> [70.0, 80.0) 21 0.2 99.5
#> [80.0, inf) 65 0.5 100.0- \([a, b)\) incluye \(a\) y excluye \(b\): cada tiempo cae en un solo intervalo
float("inf"): la última clase queda abierta- El 40,3 % tardó de 30 a menos de 40 min; el 93,0 %, menos de 50
El histograma muestra la forma: un pico entre 30 y 35 minutos y una cola a la derecha
- Barras pegadas: el eje es continuo
- Con intervalos de igual ancho, la altura es la frecuencia
- La cola llega a 201 min: 65 pedidos de 80 min o más, que casi no se ven
¿Cuál de los tres histogramas es el correcto?
Ninguno es «el» correcto. Con 25 min, la forma desaparece en tres barras; con 1 min se ve la misma forma, pero con dientes que son azar (con menos datos solo habría ruido); con 5 min se ve limpia. Conviene probar dos o tres anchos y decir cuál se usó.
Tres variables de Tingua, tres formas
Simétrica
La temperatura en Medellín: a cada lado del centro hay casi lo mismo.
Bimodal
Dos jorobas: Bogotá, con 13,9 °C de media, y las otras cuatro, de 21,9 a 28,8 °C. Hay dos grupos mezclados.
Asimétrica a la derecha
El valor del pedido: la mayoría, bajo; unos pocos, muy altos. 16 pasan de 400 mil pesos.
Antes de resumir con un número, mira la forma
La forma dice si un promedio representa a los datos o si hay grupos mezclados. Es la primera conclusión de un análisis exploratorio.
Tablas cruzadas
Dos variables a la vez: ¿llueve igual en todas las ciudades?
Una tabla cruzada cuenta los pedidos de cada combinación
pd.crosstab(pedidos["ciudad"], pedidos["lluvia"],
margins=True, margins_name="Total")
#> lluvia No Sí Total
#> ciudad
#> Barranquilla 1318 156 1474
#> Bogotá 3365 1342 4707
#> Bucaramanga 956 234 1190
#> Cali 1555 411 1966
#> Medellín 1919 744 2663
#> Total 9113 2887 12000- Filas:
ciudad· columnas:lluvia margins=True: el total de cada fila y de cada columna- Cada celda es un conteo: 1342 pedidos de Bogotá con lluvia
Una tabla cruzada admite tres porcentajes, según el total que se use
| Porcentaje | Divide entre | Responde |
|---|---|---|
Por fila · normalize="index" | el total de la ciudad | ¿Qué parte de los pedidos de Bogotá tuvo lluvia? |
Por columna · normalize="columns" | el total con lluvia (o sin ella) | ¿Qué parte de los pedidos con lluvia fue de Bogotá? |
Del total · normalize="all" | los 12 000 pedidos | ¿Qué parte de todos fue de Bogotá con lluvia? |
«En Bogotá llueve en el 46,5 % de los pedidos»: ¿es cierto?
# normalize="columns": cada columna suma 100 %
por_lluvia = pd.crosstab(pedidos["ciudad"], pedidos["lluvia"],
normalize="columns")
(por_lluvia * 100).round(1)
#> lluvia No Sí
#> ciudad
#> Barranquilla 14.5 5.4
#> Bogotá 36.9 46.5
#> Bucaramanga 10.5 8.1
#> Cali 17.1 14.2
#> Medellín 21.1 25.8No. El 46,5 % es la parte de los pedidos con lluvia que fue de Bogotá (por columna). Pesa tanto porque Bogotá tiene el 39,2 % de todos los pedidos y, además, allí llueve más que en el resto. Para saber cuánto llueve en Bogotá hay que dividir por fila.
Por fila: llueve en el 28,5 % de los pedidos de Bogotá
normalize="index": cada ciudad suma 100 %- En Barranquilla llueve en el 10,6 % de los pedidos
- La gráfica muestra solo la columna «Sí»
Por eso los 7,8 minutos de la lluvia no son solo de la lluvia
Bogotá
Llueve en el 28,5 % de sus pedidos. Sin lluvia, ya tardan 37,5 min de media.
Barranquilla
Llueve en el 10,6 % de sus pedidos. Sin lluvia, tardan 29,0 min de media.
La lluvia se concentra donde los pedidos ya tardan más. Comparando dentro de cada ciudad, la diferencia por lluvia baja a unos 6,9 min.
Antes de leer un porcentaje, pregunta: ¿sobre qué total?
El 37,4 % y el 22,1 % de cinco estrellas; el 46,5 % y el 28,5 % de Bogotá: los mismos datos, totales distintos, conclusiones distintas.
Práctica y cierre
Treinta y cinco minutos con el cuaderno (notebook): cuatro tablas que se revisan solas.
Práctica guiada: cuatro ejercicios en el notebook
medio_pago · 7 minestrato, del 1 al 6 · 8 mindistancia_km, de 2 en 2 km · 12 minAbrir el notebook de la sesión 2 en Colab. Antes del ejercicio 1: clic en [ej1] → Entorno de ejecución → Ejecutar anteriores.
¿Qué tabla o gráfico usarías?
- Cuántos pedidos se pagan con cada medio de pago
- Qué parte de los pedidos tarda menos de 50 minutos
- Cómo se reparten los valores de los pedidos
- Si la proporción de pedidos de suscriptores cambia con el estrato de la dirección
1 tabla de frecuencias y barras ordenadas por tamaño · 2 el % acumulado de la tabla agrupada del tiempo · 3 un histograma · 4 una tabla cruzada con porcentajes dentro de cada estrato (por fila, si el estrato va en las filas)
Lo que te llevas hoy
- Una distribución dice qué valores aparecen y cuántas veces
- Las relativas dividen entre el total; las acumuladas solo tienen sentido con orden
- Una continua se agrupa en intervalos \([a, b)\), y el histograma muestra su forma
- La forma es la primera conclusión: simétrica, asimétrica o con dos jorobas
- Antes de leer un porcentaje, pregunta: ¿sobre qué total?
La sesión 3 resume el centro y la dispersión
- Termina la práctica: los cuatro ejercicios se revisan solos
- Lee OpenIntro Statistics (4.ª edición), capítulo 2: la 2.1.3 (histogramas y forma) y la 2.2 repasan lo de hoy; el resto de la 2.1 prepara la sesión 3
- Escribe tres frases para la gerencia sobre el tiempo de entrega: su forma, dónde se concentra y su cola. Otra persona del curso las revisará
Próxima sesión: medidas de tendencia central y de dispersión.