Una distribución es una forma que se repite. Y lo bonito es que en la práctica casi todo se parece a una de tres 🎴
No te voy a hacer memorizar fórmulas. Vamos a ver cuál encaja con qué parte de estas ventas, y por qué.
import pandas as pd import numpy as np from scipy import stats URL = 'https://missyera.com/static/datasets/ventas-miss-yera.csv' def carga_limpia(url): """La misma del capítulo 2.""" v = pd.read_csv(url).drop_duplicates() v['ciudad'] = (v['ciudad'].str.strip().str.lower() .str.normalize('NFKD') .str.encode('ascii', 'ignore').str.decode('utf-8')) v['monto'] = pd.to_numeric(v['monto'].str.replace(',', '.')) for col in ['fecha', 'fecha_ultima_compra']: f = pd.to_datetime(v[col], format='%Y-%m-%d', errors='coerce') falta = f.isna() & v[col].notna() f[falta] = pd.to_datetime(v.loc[falta, col], format='%d/%m/%Y', errors='coerce') v[col] = f return v v = carga_limpia(URL) print('filas:', len(v))
filas: 3000
Antes de arrancar, una pregunta: ¿alguien te ha dicho alguna vez que uses la normal porque "todo tiende a la normal"? Esa frase está a medias, y la mitad que falta es la que importa 🔔
La binomial: contar éxitos en intentos fijos
La pregunta que contesta: "de 20 visitas comerciales, ¿cuántas van a cerrar?". Hay un número fijo de intentos y cada uno sale bien o mal.
la probabilidad de k éxitos en n intentos, contando de cuántas formas pueden repartirse esos k entre los n
p = v['compro'].mean() n = 20 print('probabilidad de cierre: %.4f' % p) print() for k in [8, 10, 12, 14, 16]: print('P(cerrar exactamente %2d de 20) = %.4f' % (k, stats.binom.pmf(k, n, p)))
probabilidad de cierre: 0.5777 P(cerrar exactamente 8 de 20) = 0.0503 P(cerrar exactamente 10 de 20) = 0.1380 P(cerrar exactamente 12 de 20) = 0.1761 P(cerrar exactamente 14 de 20) = 0.1013 P(cerrar exactamente 16 de 20) = 0.0237
Lo más probable es cerrar 12, y aun así solo pasa el 17,61% de las veces. Fíjate en eso, que es lo que la gente no espera: ni siquiera el resultado más probable es probable 🎲
Y esto ya sirve para algo práctico. Un comercial cierra 16 de 20 y todo el mundo aplaude. ¿Es mérito o es suerte?
print('media esperada: %.2f cierres' % (n * p)) print('desviacion: %.4f' % np.sqrt(n * p * (1 - p))) print() print('P(cerrar 16 o mas de 20) = %.6f' % (1 - stats.binom.cdf(15, n, p)))
media esperada: 11.55 cierres desviacion: 2.2089 P(cerrar 16 o mas de 20) = 0.033334
Un 3,33%. O sea que cerrar 16 de 20 pasa una de cada treinta veces solo por azar, sin que el comercial haga nada especial 😬
Si tienes treinta comerciales, cada mes va a haber uno que lo consiga. Y si lo premias, estás premiando una moneda.
Ese cálculo, "qué probabilidad hay de ver algo así de bueno por pura suerte", es exactamente un valor p. Lo formalizamos en el capítulo 12, pero ya lo acabas de hacer 😎
Poisson: contar sucesos en un periodo
La pregunta cambia: ya no hay 20 intentos. "¿Cuántas ventas voy a tener mañana?". Puede ser cualquier número.
la probabilidad de ver k sucesos en un periodo donde en promedio se ven lambda
por_dia = v.groupby(v['fecha'].dt.date).size() print('dias con actividad: %d' % len(por_dia)) print('media: %.4f ventas por dia' % por_dia.mean()) print('varianza: %.4f' % por_dia.var())
dias con actividad: 537 media: 5.5866 ventas por dia varianza: 5.4146
Media 5,5866 y varianza 5,4146. Prácticamente iguales 👀
Eso es la firma de una Poisson, y es su rareza más útil: es la única distribución común donde la media y la varianza son el mismo número. Si las mides y coinciden, tienes una Poisson delante casi seguro.
Vamos a comprobar si de verdad encaja, contando cuántos días hubo con cada cantidad de ventas:
lam = por_dia.mean() print(' ventas | observados | esperados por Poisson') for k in range(0, 12): print(' %2d | %4d | %7.2f' % (k, (por_dia == k).sum(), len(por_dia) * stats.poisson.pmf(k, lam)))
ventas | observados | esperados por Poisson
0 | 0 | 2.01
1 | 14 | 11.24
2 | 32 | 31.41
3 | 52 | 58.48
4 | 84 | 81.68
5 | 93 | 91.26
6 | 93 | 84.98
7 | 55 | 67.82
8 | 55 | 47.36
9 | 31 | 29.40
10 | 15 | 16.42
11 | 5 | 8.34
Encaja bastante bien 🎯 Observados y esperados se siguen la pista en todo el rango.
Y hay una discrepancia que merece la pena mirar: la Poisson espera unos 2 días con cero ventas y en los datos hay cero días con cero ventas.
Eso no es un fallo de la Poisson, es cómo construí la cuenta: agrupé por las fechas que aparecen en el archivo, así que un día sin ninguna venta sencillamente no existe en esa lista. Es un sesgo de selección puesto por mí sin darme cuenta, y de esos hay muchos en el capítulo 17 🕳️
La normal y por qué está en todas partes
En el capítulo 5 vimos que el monto no es normal: asimetría 1,3405, cola larga por la derecha.
Y aun así la normal va a aparecer. Mira lo que pasa si en vez de mirar ventas sueltas miro promedios de ventas:
generador = np.random.default_rng(7) montos = v['monto'].values print('las ventas sueltas: asimetria %.4f' % v['monto'].skew()) print() for n in [2, 5, 30, 100]: medias = pd.Series([generador.choice(montos, n).mean() for _ in range(2000)]) print('promedios de %3d ventas -> asimetria %+.4f | desviacion %6.2f' % (n, medias.skew(), medias.std()))
las ventas sueltas: asimetria 1.3405 promedios de 2 ventas -> asimetria +1.0091 | desviacion 531.09 promedios de 5 ventas -> asimetria +0.6173 | desviacion 331.92 promedios de 30 ventas -> asimetria +0.3223 | desviacion 138.92 promedios de 100 ventas -> asimetria +0.0518 | desviacion 75.97
Mira la columna de la asimetría bajando: 1,3405, luego 1,0091, 0,6173, 0,3223 y 0,0518 😍
Eso es el teorema central del límite, y es probablemente el resultado más importante de toda la estadística. Dice que:
los promedios se vuelven acampanados aunque los datos de los que salen no lo sean.
Por eso la normal está en todas partes: casi nunca trabajamos con datos sueltos, trabajamos con promedios, proporciones y totales. Y todos esos se comportan como una campana aunque el material de origen sea un desastre.
Fíjate también en la otra columna, la de la desviación, que baja de 531 a 76. No baja de cualquier manera:
for n in [2, 5, 30, 100]: print('n=%3d -> formula: %.2f' % (n, v['monto'].std() / np.sqrt(n)))
n= 2 -> formula: 531.74 n= 5 -> formula: 336.30 n= 30 -> formula: 137.29 n=100 -> formula: 75.20
531,74 contra 531,09. 137,29 contra 138,92. Clavado 🎯
Esa fórmula, desviación dividida entre la raíz de n, se llama error estándar y es la pieza central de todo lo que viene. Es literalmente la respuesta a "cuánto se equivoca un promedio".
Y mira lo que dice esa raíz cuadrada: para que tu promedio sea el doble de preciso necesitas cuatro veces más datos. Para diez veces más preciso, cien veces más datos. Es la razón por la que las encuestas serias tienen 1.000 personas y no 100.000: la mejora deja de compensar 💸
¿Y el famoso "con 30 basta"?
Habrás oído que con 30 datos ya vale. Míralo otra vez en la tabla: con 30 ventas la asimetría todavía es 0,3223. No es cero.
El "30" es una regla de dedo que funciona cuando los datos de partida no están muy torcidos. Con una cola como la del monto hacen falta más. Con 100 ya estamos en 0,0518, que sí es despreciable.
La versión honesta de la regla: cuanto más torcidos los datos, más promedio hace falta. Y se comprueba en tres líneas, como acabamos de hacer 🙌
El error del capítulo
Quiero una muestra de 5.000 ventas distintas para hacer el experimento más grande:
generador.choice(montos, 5000, replace=False)
ValueError: Cannot take a larger sample than population when replace is False
Solo hay 3.000 ventas, no puedo sacar 5.000 sin repetir. Justo 👍
Lo interesante es que el experimento de arriba sí repetía
(replace=True es lo que hace choice por defecto), y eso
no es un descuido: es la técnica. Se llama remuestreo, y consiste en tratar tus
datos como si fueran la población y sacar muestras con reposición.
Y ojo con el pariente silencioso de este error:
print('P(cerrar 25 de 20 intentos) =', stats.binom.pmf(25, 20, p)) print('media de una binomial con p=1.5:', stats.binom(20, 1.5).mean())
P(cerrar 25 de 20 intentos) = 0.0 media de una binomial con p=1.5: nan
Pedirle 25 éxitos de 20 intentos devuelve 0.0, que es correcto pero se parece
mucho a "es muy improbable" cuando en realidad es "eso no puede pasar". Y una
probabilidad de 1,5 devuelve nan sin quejarse 😑
Cuál usar, en una tabla
| Si cuentas | Distribución | Señal para reconocerla |
|---|---|---|
| Éxitos en n intentos fijos | Binomial | Hay un máximo posible |
| Sucesos en un periodo | Poisson | Media y varianza parecidas |
| Promedios, totales, proporciones | Normal | Casi siempre, por el TLC |
| Tiempo hasta que pase algo | Exponencial | Muchos cortos, pocos larguísimos |
Y dos más, de pedirle a una distribución algo imposible
generador.poisson(-3)
ValueError: lam < 0 or lam is NaN
La Poisson cuenta cosas que pasan, y su parámetro es cuántas pasan en promedio. Menos tres pedidos por día no existe. Cuando una distribución se queja del parámetro, casi siempre te está diciendo que le pediste algo que el mundo no puede hacer.
stats.binom.rvs(10, 1.4, size=5)
ValueError: Domain error in arguments. The `scale` parameter must be positive for all distributions, and many distributions have restrictions on shape parameters. Please see the `scipy.stats.binom` documentation for details.
Lo mismo con la binomial: su segundo parámetro es una probabilidad y 1,4 no lo es. El mensaje es largo y genérico porque scipy usa el mismo para todas sus distribuciones, así que lo útil está al final, en el nombre de la que se quejó 🔍
Practica 💪
1. ¿Es raro cerrar 16 de 20 dos meses seguidos?
Ya sabemos que cerrar 16 de 20 pasa el 3,33% de las veces. Calcula la probabilidad de que le pase al mismo comercial dos meses seguidos, y la de que le pase a alguno de 30 comerciales en un mes.
una_vez = 1 - stats.binom.cdf(15, 20, p) print('un comercial, un mes: %.6f' % una_vez) print('el mismo, dos meses: %.6f' % (una_vez ** 2)) print('alguno de 30, en un mes: %.6f' % (1 - (1 - una_vez) ** 30))
un comercial, un mes: 0.033334 el mismo, dos meses: 0.001111 alguno de 30, en un mes: 0.638347
Los tres números cuentan historias distintas 📖
Que el mismo lo repita dos meses seguidos tiene una probabilidad de 0,11%. Eso ya es difícil de explicar con suerte, y ahí sí empezaría a mirarle la técnica.
Pero mira el tercero: en un equipo de 30, la probabilidad de que alguien lo consiga es del 63,83%. O sea que es lo más normal del mundo.
Y esa es la trampa de las comparaciones múltiples, que tiene capítulo propio (el 14). Un resultado raro deja de ser raro en cuanto le das muchas oportunidades de ocurrir 🎰
2. ¿Encaja Poisson también por segmento?
Comprueba la firma de la Poisson (media parecida a varianza) en las ventas diarias de cada segmento.
for seg, g in v.groupby('segmento'): dia = g.groupby(g['fecha'].dt.date).size() print('%-11s media %.4f | varianza %.4f | razon %.3f' % (seg, dia.mean(), dia.var(), dia.var() / dia.mean()))
Bodega media 1.8556 | varianza 1.0607 | razon 0.572 Horeca media 1.7966 | varianza 0.8517 | razon 0.474 Mayorista media 1.8337 | varianza 0.9282 | razon 0.506 Minimarket media 1.9632 | varianza 1.2296 | razon 0.626
Aquí la razón está entre 0,47 y 0,63, no en 1. Ya no es Poisson 🤔
Una varianza menor que la media significa que los días se parecen entre ellos más de lo que el azar puro permitiría. A eso se le llama subdispersión.
Y la explicación es la misma trampa de antes: al agrupar por segmento, los días sin ninguna venta de ese segmento desaparecen de la cuenta. Estoy recortando justo los días flojos, así que los que quedan se parecen demasiado.
Buena lección: cuando una distribución deja de encajar, sospecha antes de tus datos que de la teoría 🔍
3. El TLC con la peor columna posible
Aplica el mismo experimento a algo mucho más torcido que el
monto: la columna compro, que solo tiene ceros y unos. ¿Cuántos
hacen falta?
ceros_y_unos = v['compro'].values for n in [5, 30, 100, 500]: medias = pd.Series([generador.choice(ceros_y_unos, n).mean() for _ in range(2000)]) print('promedios de %3d -> asimetria %+.4f | valores distintos %d' % (n, medias.skew(), medias.nunique()))
promedios de 5 -> asimetria -0.1134 | valores distintos 6 promedios de 30 -> asimetria -0.0899 | valores distintos 18 promedios de 100 -> asimetria -0.0079 | valores distintos 34 promedios de 500 -> asimetria -0.0074 | valores distintos 70
Esto me sorprendió: converge más rápido que el monto, aunque los datos de partida son mucho más feos 😲
Con solo 5 la asimetría ya está en -0,11, que al monto le costó llegar con 30 y pico. Y con 100 estamos en -0,0079, diez veces más cerca de cero que el monto con las mismas 100.
El motivo es que lo que frena al TLC no es que los datos sean raros, sino que tengan cola. Una columna 0/1 no tiene cola: no hay ningún valor extremo que pueda arrastrar un promedio. El monto sí, y por eso tarda.
Mira también la última columna, la de valores distintos: con n=5 solo hay 6 promedios posibles (0, 0.2, 0.4...). La campana está ahí pero dibujada a brochazos 🖌️
4. El error estándar, y cuánto cuesta mejorarlo
Calcula cuántas ventas necesitas para que el error estándar del promedio baje a 50, a 25 y a 10 soles.
s = v['monto'].std() for objetivo in [100, 50, 25, 10]: print('para un error estandar de %3d soles hacen falta %8.0f ventas' % (objetivo, (s / objetivo) ** 2))
para un error estandar de 100 soles hacen falta 57 ventas para un error estandar de 50 soles hacen falta 226 ventas para un error estandar de 25 soles hacen falta 905 ventas para un error estandar de 10 soles hacen falta 5655 ventas
De 100 a 50 soles de precisión: pasas de 57 a 226 ventas. De 50 a 25: de 226 a 905. Cada vez que quieres el doble de precisión, cuadruplicas la muestra 💸
Ese es el cálculo que hay detrás de "¿cuántos clientes encuesto?", y es de lo más útil que te llevas del libro. Lo normal es que alguien pida una precisión absurda sin saber que cuesta cinco mil respuestas.
Fíjate en que la fórmula solo necesita dos cosas: la desviación que esperas y la precisión que quieres. Puedes hacerlo antes de recoger un solo dato 📋
5. Simula un mes de ventas
Con la Poisson de las ventas diarias y la distribución de montos, simula 30 días y mira cuánto varía el total mensual.
lam = por_dia.mean() totales = [] for _ in range(2000): ventas_del_mes = generador.poisson(lam, 30).sum() totales.append(generador.choice(montos, ventas_del_mes).sum()) totales = pd.Series(totales) print('total mensual simulado: media %.0f | desviacion %.0f' % (totales.mean(), totales.std())) print('el 90%% de los meses cae entre %.0f y %.0f' % (totales.quantile(0.05), totales.quantile(0.95)))
total mensual simulado: media 134673 | desviacion 14433 el 90% de los meses cae entre 111598 y 158882
Ahora compáralo con lo que medimos en el capítulo 1: los meses reales iban de 103.474 a 164.313 soles 🤯
La simulación dice que el 90% de los meses debería caer entre 111.598 y 158.882, con una media de 134.673.
La simulación, que no sabe nada de meses y solo conoce la tasa diaria y la forma de los montos, cae casi encima del rango real. Se queda un poco corta en las dos puntas, y tiene sentido: los meses de verdad tienen distinto número de días laborables y campañas, cosas que la simulación no sabe.
Y eso cierra el círculo del capítulo 1. Aquella variación mensual del 14,41% que parecía tan dramática es exactamente lo que produce el azar con esta tasa de ventas y estos montos. No hacía falta ninguna explicación de negocio, y ahora tenemos la prueba en vez de la sospecha 🎯
6. ¿Cuántas ventas negativas esperabas?
Sabemos que hay 21 ventas negativas en 3.000. Si fueran cosa del azar con esa tasa, ¿cuánto variarían de un archivo a otro?
tasa = (v['monto'] < 0).mean() esperadas = tasa * len(v) print('tasa: %.5f -> esperadas %.1f' % (tasa, esperadas)) print('desviacion de una Poisson: %.2f' % np.sqrt(esperadas)) print() print('rango tipico: de %.0f a %.0f' % (esperadas - 2 * np.sqrt(esperadas), esperadas + 2 * np.sqrt(esperadas))) print('P(ver 40 o mas) = %.6f' % (1 - stats.poisson.cdf(39, esperadas)))
tasa: 0.00700 -> esperadas 21.0 desviacion de una Poisson: 4.58 rango tipico: de 12 a 30 P(ver 40 o mas) = 0.000144
La Poisson tiene una propiedad muy cómoda: su desviación es la raíz de su media. Con 21 esperadas, la desviación es 4,58.
O sea que si el mes que viene aparecen 28 ventas negativas, tranqui: entra dentro de lo normal. Si aparecen 40, ahí sí ha pasado algo, porque eso tiene una probabilidad de 0,014% 🚨
Este cálculo es la forma más barata que conozco de montar una alerta. No hace falta ningún modelo: cuentas lo que suele pasar, sacas la raíz, y avisas cuando te separas más de dos o tres de esas 📟
7. El teorema central del límite, a mano
Promedia 1, 2, 5 y 30 pedidos al azar, dos mil veces cada uno, y mira cuánto varían esos promedios.
g2 = np.random.default_rng(11) for n in [1, 2, 5, 30]: medias = [g2.choice(v['monto'].values, n).mean() for _ in range(2000)] print('promediando %2d pedidos: desviacion de las medias %7.2f' % (n, np.std(medias))) print() print('la desviacion de un pedido suelto es %.2f' % v['monto'].std())
promediando 1 pedidos: desviacion de las medias 733.73 promediando 2 pedidos: desviacion de las medias 525.72 promediando 5 pedidos: desviacion de las medias 339.30 promediando 30 pedidos: desviacion de las medias 135.72 la desviacion de un pedido suelto es 751.99
Ahí está la raíz cuadrada, escondida a plena vista 🤓
Con 30 pedidos la desviación baja a 135,72. Y 751,99 dividido entre la raíz de 30 da 137,3, que es lo mismo salvo por el azar de las dos mil repeticiones. Para que el promedio sea el doble de estable hace falta cuatro veces más gente, y por eso las encuestas caras son tan caras.
Este número reaparece en el capítulo 10 con el nombre de error estándar, y ahora ya sabes de dónde sale 📐
8. ¿Los pedidos por mes son Poisson?
Cuenta los pedidos de cada mes y compara su media con su varianza.
por_mes = v.groupby(v['fecha'].dt.month).size() print('pedidos por mes:') print(por_mes.to_string()) print() print('media %.1f, varianza %.1f' % (por_mes.mean(), por_mes.var()))
pedidos por mes: fecha 1 339 2 306 3 359 4 323 5 365 6 292 7 164 8 156 9 179 10 181 11 177 12 159 media 250.0, varianza 7536.4
Media 250 y varianza 7.536. Ni de cerca 🙅♀️
La Poisson tiene una propiedad que la delata: su media y su varianza son el mismo número. Aquí la varianza es treinta veces la media, así que estos conteos no son Poisson y no hay que forzarlos.
Y mira la lista, que se ve el porqué sin ninguna cuenta: de enero a junio ronda los 330 y de julio a diciembre los 170. No es azar, es que el segundo semestre vende la mitad. La Poisson supone una tasa constante, y aquí hay dos tasas 📆
El teorema que casi todo el mundo cita al revés
Y ahora una que se oye mucho en reuniones y que casi nunca se dice bien. Las dos mitades son verdad y no significan lo que parece 🎯
La trampa
Necesitas cuántas ventas grandes esperar para preparar el stock. Tienes la media y la desviación, así que usas la normal, que es lo que se hace.
from scipy import stats mu, sd = v['monto'].mean(), v['monto'].std() segun_campana = 1 - stats.norm.cdf(3000, mu, sd) real = (v['monto'] > 3000).mean() print(round(segun_campana * 100, 2), round(real * 100, 2)) # 0.17 1.23
Qué está mal
Siete veces más ventas grandes de las que la campana predice 📦
La normal se define entera con la media y la desviación, así que en cuanto le das esos dos números te contesta lo que sea, aunque tus datos no tengan nada que ver con una campana. Y el monto tiene cola a la derecha, o sea justo la zona donde estás preguntando.
Y fíjate en lo que sale mal en la vida real: te quedas corta de stock en las ventas grandes, que son las que más facturan. El error no se reparte, se concentra en lo que más importa.
Para preguntas sobre las colas, la campana es la peor herramienta posible. Lo que uso es el dato: (v['monto'] > 3000).mean(), que no supone ninguna forma, o los percentiles altos si necesito un umbral. La normal sirve para el centro, no para los bordes.
Comprueba que lo tienes
Las ventas diarias tienen media 5,5866 y varianza 5,4146. ¿Qué te dice eso?
- Que se comportan como una Poisson, que es la única común donde media y varianza coinciden
- Que la varianza está mal calculada
- Que los datos son normales
- Que hay poca variación día a día
Lo que te llevas
- 🎯 Binomial para éxitos en intentos fijos. Cerrar 16 de 20 pasa el 3,33% de las veces por puro azar, y en un equipo de 30 le pasa a alguien el 63,83% de los meses.
- 📅 Poisson para sucesos en un periodo. Su firma es media parecida a varianza: aquí 5,5866 y 5,4146.
- 🔔 El teorema central del límite: los promedios se acampanan aunque los datos no. La asimetría bajó de 1,3405 a 0,0518 promediando de a 100.
- 📐 Error estándar = desviación entre raíz de n. Para el doble de precisión, cuatro veces más datos.
- ⚠️ El "con 30 basta" es una regla de dedo. Con esta cola, a los 30 la asimetría todavía era 0,3223.
- 🎰 Simulando solo con la tasa diaria y la forma de los montos salió un rango mensual de 111.598 a 158.882, y los meses reales fueron de 103.474 a 164.313.
Y si de todo el capítulo te llevas una sola frase, que sea esta:
El teorema central del límite habla de los promedios, no de tus datos. No son lo mismo.
Todo lo de este capítulo se calcula con scipy.stats y numpy, y si
esas dos te suenan a chino, empiezan desde cero en el
libro de Python 🐍
Qué viene ahora
Ya tenemos el error estándar, que es la pieza que faltaba. En el capítulo 10 la usamos para lo que todo el mundo quiere: poner un margen de error a un número y decir "está entre esto y esto" 📊
Preguntas frecuentes
¿Qué es la distribución binomial?
La que cuenta cuántos éxitos salen en un número fijo de intentos, cuando cada intento sale bien con la misma probabilidad. Cuántos de cien visitantes compran es exactamente eso.
¿Qué es la distribución de Poisson?
La que cuenta cuántas veces pasa algo en un rato, cuando pasa poco y al azar. Cuántos reclamos llegan en una hora es el caso de manual, y el de verdad también.
¿Cuándo uso binomial y cuándo Poisson?
Binomial cuando sabes cuántos intentos hubo. Poisson cuando no hay intentos que contar, solo un periodo de tiempo y cosas que van llegando.
¿Qué es la distribución t de Student?
La hermana de la normal para cuando tienes pocos datos. Es más ancha, o sea más prudente, y se va pareciendo a la normal a medida que la muestra crece.
¿Qué es el teorema central del límite?
Que si promedias muestras de cualquier cosa, esos promedios se reparten como una campana aunque los datos originales no lo hagan. Es la razón de que la normal aparezca en todas partes.
¿Qué es el error estándar?
La desviación estándar de los promedios de muestra, no de los datos. Dice cuánto bailaría tu promedio si repitieras el muestreo, y es lo que hay detrás del margen de error.
Practica este capítulo 📓
Todo el código de arriba en un cuaderno que corre de principio a fin, y los ejercicios con una celda vacía para que los hagas tú. Se abre en Google Colab de un clic y no hay que instalar nada. Donde veas %%revisa, escribe tu respuesta y el cuaderno te dice si te salió.
¿Prefieres trabajar en tu máquina? Bájate el cuaderno de práctica o el de soluciones. Todos están también en github.com/soymissyera/MissYeraEjercicios.