{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Cuándo la campana no aplica\n",
    "\n",
    "La distribución normal, cómo se comprueba de verdad, y por qué el test de normalidad dice que no en cuanto tienes datos.\n",
    "\n",
    "Cuaderno de práctica del capítulo 5 de **Estadística desde cero**, de Miss Yera.\n",
    "\n",
    "Corre de arriba abajo. Si lo abres en Google Colab no necesitas instalar nada.\n",
    "\n",
    "Capítulo completo: https://missyera.com/guias/estadistica-desde-cero/la-campana/\n",
    "\n",
    "Los ejercicios están al final y traen una celda vacía debajo de cada uno. Las\n",
    "respuestas viven en el cuaderno de soluciones, y merece la pena pelearse un\n",
    "rato antes de abrirlo 💛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Antes de empezar\n",
    "\n",
    "Esta celda baja el ayudante que corrige tus ejercicios. Después, en cada\n",
    "ejercicio que se pueda corregir solo, vas a ver `%%revisa` arriba de la celda:\n",
    "escribe tu respuesta debajo, ejecuta, y te digo si te salió 💛"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import urllib.request\n",
    "\n",
    "# El ayudante de los cuadernos. Trae la corrección de los ejercicios y, en los\n",
    "# capítulos de consola, la celda mágica que ejecuta los comandos. Se baja en\n",
    "# vez de venir pegado aquí para que siempre sea el último.\n",
    "urllib.request.urlretrieve(\n",
    "    \"https://missyera.com/static/cuadernos/revisa.py\", \"revisa.py\")\n",
    "import revisa\n",
    "revisa.carga({\n",
    "    2: \"Qm9kZWdhICAgICBhc2ltZXRyaWEgLTAuNzc1MiB8IGN1cnRvc2lzICAzLjQ1OTAgfCBtaW5pbW8gIC0yMjQuNjEKTWF5b3Jpc3RhICBhc2ltZXRyaWEgLTAuNDU2MCB8IGN1cnRvc2lzICAzLjA1MTAgfCBtaW5pbW8gLTI0OTcuNzI=\",\n",
    "    3: \"Y3VhbnRpbCAwLjA1IC0+IG9ic2VydmFkbyAgIDExOS4wMyB8IG5vcm1hbCAgLTQzMy4xNSB8IGVycm9yICArNTUyLjE4CmN1YW50aWwgMC4yNSAtPiBvYnNlcnZhZG8gICAyNTIuNjkgfCBub3JtYWwgICAyOTYuNTUgfCBlcnJvciAgIC00My44NgpjdWFudGlsIDAuNTAgLT4gb2JzZXJ2YWRvICAgNTMzLjYzIHwgbm9ybWFsICAgODAzLjc2IHwgZXJyb3IgIC0yNzAuMTMKY3VhbnRpbCAwLjc1IC0+IG9ic2VydmFkbyAgMTA2OC42OCB8IG5vcm1hbCAgMTMxMC45NyB8IGVycm9yICAtMjQyLjI5CmN1YW50aWwgMC45NSAtPiBvYnNlcnZhZG8gIDI0MzEuNzYgfCBub3JtYWwgIDIwNDAuNjcgfCBlcnJvciAgKzM5MS4wOApjdWFudGlsIDAuOTkgLT4gb2JzZXJ2YWRvICAzMDU4LjU5IHwgbm9ybWFsICAyNTUzLjE1IHwgZXJyb3IgICs1MDUuNDQ=\",\n",
    "    4: \"bWVkaWEgZGUgejogICAgICAtMC4wMDAwMDAKZGVzdmlhY2lvbiBkZSB6OiAxLjAwMDAwMAphc2ltZXRyaWEgZGUgejogIDEuMzQwNQoKbGEgdmVudGEgbWFzIGdyYW5kZSBlc3RhIGEgNC41NyBkZXN2aWFjaW9uZXMKbGEgbWFzIGNoaWNhLCBhIC00LjM5\",\n",
    "    5: \"bj0gICAxMDAgY29uIDElIGRlIGludHJ1c29zIC0+IHAgPSAwLjAwMDAwNQpuPSAgIDUwMCBjb24gMSUgZGUgaW50cnVzb3MgLT4gcCA9IDAuMDAwMDAwCm49ICAyMDAwIGNvbiAxJSBkZSBpbnRydXNvcyAtPiBwID0gMC4wMDAwMDAKbj0gIDUwMDAgY29uIDElIGRlIGludHJ1c29zIC0+IHAgPSAwLjAwMDAwMA==\",\n",
    "    6: \"bW9udG8gICAgICAgICBhc2ltZXRyaWEgKzEuMzQwNSB8IGN1cnRvc2lzICsxLjU0NTggLT4gY29sYSBsYXJnYSBoYWNpYSBsYSBkZXJlY2hhCnVuaWRhZGVzICAgICAgYXNpbWV0cmlhICswLjE4NDMgfCBjdXJ0b3NpcyAtMC4zMzUxIC0+IHJhem9uYWJsZW1lbnRlIGFjYW1wYW5hZGEKc2F0aXNmYWNjaW9uICBhc2ltZXRyaWEgLTAuMDE0OSB8IGN1cnRvc2lzIC0xLjMwODkgLT4gcGxhbmEsIHBhcmVjZSB1bmlmb3JtZQpkZXNjdWVudG8gICAgIGFzaW1ldHJpYSAtMC4wMTU3IHwgY3VydG9zaXMgLTEuMTYwNCAtPiBwbGFuYSwgcGFyZWNlIHVuaWZvcm1l\",\n",
    "    7: \"bW9udG8gICAgICAgICBkZW50cm8gZGUgdW5hIGRlc3ZpYWNpb246IDgxLjglICAgKGxhIGNhbXBhbmEgZGljZSA2OCwzJSkKdW5pZGFkZXMgICAgICBkZW50cm8gZGUgdW5hIGRlc3ZpYWNpb246IDY4LjclICAgKGxhIGNhbXBhbmEgZGljZSA2OCwzJSkKc2F0aXNmYWNjaW9uICBkZW50cm8gZGUgdW5hIGRlc3ZpYWNpb246IDU5LjQlICAgKGxhIGNhbXBhbmEgZGljZSA2OCwzJSk=\",\n",
    "    8: \"YXNpbWV0cmlhIGRlbCBtb250bzogICAgICAxLjM0MAphc2ltZXRyaWEgZGVsIGxvZ2FyaXRtbzogIC0wLjE1OApsYSBwcnVlYmEgZGUgbm9ybWFsaWRhZCBzb2JyZSBlbCBsb2dhcml0bW86IHAgPSAwLjAwMDAxMQ==\",\n",
    "}, lenguaje=\"python\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La campana de Gauss es la figura más famosa de la estadística, y también la\n",
    "más aplicada donde no toca 🔔"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "f(x)=1σ2πe−12(x−μσ)2\n",
    "\n",
    "la altura de la campana en cada punto, que solo depende de a cuántas desviaciones del centro estás"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Importa por una razón muy concreta: **media docena de herramientas del\n",
    "libro la dan por supuesta**. La regla del 68%, los intervalos de\n",
    "confianza clásicos, la prueba t, la detección de atípicos por desviaciones. Si\n",
    "tus datos no son campana, esas herramientas no se rompen con un error rojo: te\n",
    "devuelven un número equivocado con toda la calma 😶\n",
    "\n",
    "Así que vamos a aprender a comprobarlo. Y de paso vamos a ver que la forma\n",
    "\"oficial\" de comprobarlo, la prueba de normalidad, es bastante inútil.\n",
    "\n",
    "Y contéstate esto antes de seguir: **¿cuántas veces has usado la regla del 68% sin mirar si tus datos eran una campana?** Yo, muchas, y por eso este capítulo existe 🔔"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Primero, mirarlo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from scipy import stats\n",
    "\n",
    "URL = 'https://missyera.com/static/datasets/ventas-miss-yera.csv'\n",
    "\n",
    "\n",
    "def carga_limpia(url):\n",
    "    \"\"\"La misma del capítulo 2.\"\"\"\n",
    "    v = pd.read_csv(url).drop_duplicates()\n",
    "    v['ciudad'] = (v['ciudad'].str.strip().str.lower()\n",
    "                   .str.normalize('NFKD')\n",
    "                   .str.encode('ascii', 'ignore').str.decode('utf-8'))\n",
    "    v['monto'] = pd.to_numeric(v['monto'].str.replace(',', '.'))\n",
    "    for col in ['fecha', 'fecha_ultima_compra']:\n",
    "        f = pd.to_datetime(v[col], format='%Y-%m-%d', errors='coerce')\n",
    "        falta = f.isna() & v[col].notna()\n",
    "        f[falta] = pd.to_datetime(v.loc[falta, col], format='%d/%m/%Y',\n",
    "                                  errors='coerce')\n",
    "        v[col] = f\n",
    "    return v\n",
    "\n",
    "\n",
    "v = carga_limpia(URL)\n",
    "\n",
    "\n",
    "def histograma(serie, tramos=10):\n",
    "    \"\"\"Un histograma de texto, que se ve igual de bien y no necesita gráficos.\"\"\"\n",
    "    cuenta, bordes = np.histogram(serie.dropna(), bins=tramos)\n",
    "    for i in range(tramos):\n",
    "        print('%8.0f a %8.0f | %4d %s'\n",
    "              % (bordes[i], bordes[i + 1], cuenta[i], '#' * int(cuenta[i] / 20)))\n",
    "\n",
    "\n",
    "histograma(v['monto'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Con eso ya sabes que `monto` no es una campana, y no hizo falta\n",
    "ninguna prueba 👀\n",
    "\n",
    "Una campana sube y baja simétrica. Esto sube de golpe, tiene su pico entre\n",
    "196 y 869, y luego baja con una **cola larga por la derecha** que\n",
    "llega hasta 4.237. Y por la izquierda hay cinco filas sueltas en territorio\n",
    "negativo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Los dos números que resumen la forma"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for col in ['monto', 'unidades', 'satisfaccion', 'descuento']:\n",
    "    s = v[col].dropna()\n",
    "    print('%-13s asimetria %7.4f | curtosis %7.4f' % (col, s.skew(), s.kurtosis()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**La asimetría** dice hacia dónde cae la cola. Cero es\n",
    "simétrico, positivo es cola a la derecha, negativo a la izquierda. Como regla de\n",
    "campo, entre -0,5 y 0,5 es bastante simétrico y por encima de 1 la cola ya es\n",
    "evidente.\n",
    "\n",
    "**La curtosis** (la que devuelve pandas es la de exceso) dice si\n",
    "la campana es puntiaguda o achatada. Cero es como la normal, positivo es más\n",
    "picuda con colas más pesadas, negativo es más plana.\n",
    "\n",
    "Ahora léelo como si fueran cuatro personas 🙂\n",
    "\n",
    "- 💰 `monto`: asimetría 1,3405. Cola a la derecha, confirmado.\n",
    "\n",
    "- 📦 `unidades`: 0,1843 y -0,3351. Esto sí parece una campana.\n",
    "\n",
    "- ⭐ `satisfaccion`: simétrica pero con curtosis -1,3089, o sea muy\n",
    "plana. Eso no es campana, es una meseta: los cinco valores salen casi igual de\n",
    "veces.\n",
    "\n",
    "- 🏷️ `descuento`: lo mismo, plana."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ahora la prueba oficial, y la decepción"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La prueba de Shapiro-Wilk contesta \"¿podrían estos datos venir de una\n",
    "normal?\". Si el valor p es chico, la respuesta es no.\n",
    "\n",
    "Se la aplicamos a `unidades`, la que mejor pinta tenía:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(stats.shapiro(v['unidades']))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "p = 0,00000000000000052 😬\n",
    "\n",
    "O sea que la prueba dice, con toda la contundencia del mundo, que\n",
    "`unidades` **no** es normal. La misma columna que tenía\n",
    "asimetría 0,18 y que en el capítulo 4 cumplía la regla del 68% clavada\n",
    "(68,70%).\n",
    "\n",
    "¿Quién miente? Ninguno. Mira lo que pasa cuando le doy los mismos datos en\n",
    "trozos de distinto tamaño:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for n in [20, 50, 100, 300, 1000, 3000]:\n",
    "    muestra = v['unidades'].sample(n, random_state=7)\n",
    "    print('con %5d filas -> p = %.6f' % (n, stats.shapiro(muestra).pvalue))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahí está el truco entero 🎩\n",
    "\n",
    "Los mismos datos. Con 50 filas la prueba dice \"normal, adelante\". Con 1.000\n",
    "dice \"de ninguna manera\". **La columna no cambió: cambió cuánta evidencia\n",
    "tienes.**\n",
    "\n",
    "Y no es que Shapiro sea mala. Mira qué pasa con datos que *sí* vienen\n",
    "de una normal de verdad:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "generador = np.random.default_rng(7)\n",
    "\n",
    "for n in [100, 1000, 3000]:\n",
    "    print('normal de verdad con %5d datos -> p = %.4f'\n",
    "          % (n, stats.shapiro(generador.normal(size=n)).pvalue))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Con datos normales de verdad, el p se queda alto por muchos datos que le\n",
    "des ✅\n",
    "\n",
    "O sea que la prueba funciona perfectamente. Lo que pasa es que responde a una\n",
    "pregunta que no es la tuya:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| Lo que crees que preguntas | Lo que la prueba contesta |\n",
    "|---|---|\n",
    "| ¿Mis datos son normales? | ¿Tengo evidencia suficiente para afirmar que no lo son exactamente? |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ningún dato real es *exactamente* normal. Con suficientes filas\n",
    "siempre se nota. Por eso, en la práctica: **mira el histograma y la\n",
    "asimetría, y usa la prueba como acompañamiento, nunca como sentencia** 🧭\n",
    "\n",
    "Guárdate esta idea, porque es la misma que va a salir en el capítulo 14 con\n",
    "todas las pruebas: *significativo* no quiere decir *importante*.\n",
    "Con muchos datos, todo sale significativo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que sí decide: comparar cuantiles"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mi comprobación favorita, porque contesta la pregunta práctica de verdad:\n",
    "\"¿me equivoco mucho si trato esto como normal?\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "u = v['unidades']\n",
    "m, s = u.mean(), u.std()\n",
    "\n",
    "for q in [0.05, 0.25, 0.50, 0.75, 0.95]:\n",
    "    print('cuantil %.2f -> observado %6.2f | si fuera normal %6.2f'\n",
    "          % (q, u.quantile(q), stats.norm.ppf(q, m, s)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mira qué cerca 😍 En los extremos, que es donde más duele equivocarse, la\n",
    "diferencia es de una décima de unidad.\n",
    "\n",
    "Entonces, ¿es `unidades` normal? Formalmente no, y Shapiro tiene\n",
    "razón. ¿Puedo tratarla como normal para decidir cosas de negocio?\n",
    "**Perfectamente.**\n",
    "\n",
    "Esa es la respuesta madura, y es la que quiero que te lleves: la normalidad\n",
    "no es un sí o un no, es *cuánto me cuesta suponerla* 💡"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Cuando no hay campana: transformar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Volvamos a `monto`, que sí estaba torcido de verdad. Hay un truco\n",
    "clásico para colas por la derecha: aplicar el logaritmo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "positivos = v.loc[v['monto'] > 0, 'monto']\n",
    "\n",
    "print('filas positivas: %d de %d' % (len(positivos), len(v)))\n",
    "print('asimetria antes:   %.4f' % positivos.skew())\n",
    "print('asimetria despues: %.4f' % np.log(positivos).skew())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "De 1,4278 a -0,1585. El logaritmo aplasta la cola y deja algo casi\n",
    "simétrico 🪄\n",
    "\n",
    "Funciona porque el logaritmo comprime los números grandes mucho más que los\n",
    "chicos: la distancia entre 100 y 1.000 pasa a ser la misma que entre 1.000 y\n",
    "10.000.\n",
    "\n",
    "Fíjate en el precio de la operación: hay que tirar 21 filas, las que tienen\n",
    "monto negativo o cero, porque el logaritmo de un número negativo no existe.\n",
    "Nunca transformes sin contar cuántas filas te dejas 🧾\n",
    "\n",
    "Y hay un regalo escondido en esto:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('mediana de las positivas:  %.2f' % positivos.median())\n",
    "print('exp(media del logaritmo):  %.2f' % np.exp(np.log(positivos).mean()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Casi el mismo número. Lo que hiciste al promediar en escala logarítmica y\n",
    "volver fue calcular la **media geométrica**, la del capítulo 3. Y\n",
    "en una distribución con cola por la derecha, la media geométrica cae encima de\n",
    "la mediana 🎯\n",
    "\n",
    "Lo que cuesta transformar es la interpretación. Después de la\n",
    "transformación tus resultados están en \"log de soles\", que no significa nada\n",
    "para nadie. Hay que deshacerla para contar el resultado, y ahí es donde se\n",
    "cometen errores. Yo transformo solo cuando la herramienta lo necesita de\n",
    "verdad."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El error del capítulo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Vamos a intentar partir la satisfacción en diez tramos iguales, que es lo que\n",
    "harías para ver su forma con más detalle:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Esto revienta a propósito.** Se ejecuta dentro de un `try` para que puedas seguir con \"ejecutar todo\" y aun así ver la queja."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    pd.qcut(v['satisfaccion'], 10)\n",
    "except Exception as e:\n",
    "    print(f'{type(e).__name__}: {e}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y la queja que tiene que salir es esta:\n",
    "\n",
    "```\n",
    "ValueError: Bin edges must be unique: Index([1.0, 1.0, 1.0, 2.0, 3.0, 3.0, 4.0, 4.0, 5.0, 5.0, 5.0], dtype='float64', name='satisfaccion').\n",
    "You can drop duplicate edges by setting the 'duplicates' kwarg\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Este error es de los buenos, porque te está enseñando algo del dato y no del\n",
    "código 🎓\n",
    "\n",
    "`qcut` parte en tramos con *la misma cantidad de filas cada\n",
    "uno*. Para hacer diez tramos necesita diez cortes distintos, y\n",
    "`satisfaccion` solo tiene cinco valores posibles. Al buscar el borde\n",
    "del decil 10 y del decil 20 encuentra el mismo 1.0 en los dos, y se planta.\n",
    "\n",
    "La tentación es hacerle caso al mensaje y poner\n",
    "`duplicates='drop'`. No lo hagas sin pensar: eso taparía el problema y\n",
    "te dejaría tramos de tamaños muy distintos disfrazados de deciles.\n",
    "\n",
    "Lo correcto es aceptar lo que el error te está diciendo: **esa columna\n",
    "no tiene diez tramos, tiene cinco categorías**. Se cuenta con\n",
    "`value_counts` y se acabó."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Y dos más, de intentar meter en la campana lo que no cabe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Esto revienta a propósito.** Se ejecuta dentro de un `try` para que puedas seguir con \"ejecutar todo\" y aun así ver la queja."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    stats.norm.fit(v['ciudad'])\n",
    "except Exception as e:\n",
    "    print(f'{type(e).__name__}: {e}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y la queja que tiene que salir es esta:\n",
    "\n",
    "```\n",
    "TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ajustar una normal es buscar la media y la desviación que mejor encajan, y las dos son cuentas. Sobre nombres de ciudad no hay nada que ajustar, y scipy lo dice con un mensaje bastante peor de lo que merece la pregunta 😅"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Esto revienta a propósito.** Se ejecuta dentro de un `try` para que puedas seguir con \"ejecutar todo\" y aun así ver la queja."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    stats.zscore(v['ciudad'])\n",
    "except Exception as e:\n",
    "    print(f'{type(e).__name__}: {e}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y la queja que tiene que salir es esta:\n",
    "\n",
    "```\n",
    "TypeError: unsupported operand type(s) for /: 'str' and 'int'\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La puntuación z es restar la media y dividir entre la desviación, y ahí se ve la división imposible en el mensaje. Todo este capítulo vive sobre variables numéricas, y las categóricas tienen su propio capítulo en el 13."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Practica 💪"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. ¿De qué forma es la satisfacción?\n",
    "\n",
    "Píntala con el histograma de texto y di qué forma tiene."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. La normalidad dentro de un segmento\n",
    "\n",
    "En el capítulo 3 vimos que dentro de cada segmento la media\n",
    "y la mediana coincidían. ¿Quiere eso decir que cada segmento es normal?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 2\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Cuánto te cuesta suponer normalidad en el monto\n",
    "\n",
    "Haz con `monto` la comparación de cuantiles que\n",
    "hicimos con `unidades`. ¿Dónde se rompe más?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 3\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Normaliza tú un dato: la puntuación z\n",
    "\n",
    "Convierte el monto a \"cuántas desviaciones estoy del\n",
    "promedio\" y comprueba qué le pasa a la media y a la desviación."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 4\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. El test que se rinde con muchos datos\n",
    "\n",
    "Reproduce el fenómeno del capítulo con datos fabricados:\n",
    "genera una normal con un defecto minúsculo y mira desde qué tamaño lo detecta\n",
    "Shapiro."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 5\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. Tu chequeo de forma, en una función\n",
    "\n",
    "Junta todo en algo que puedas correr sobre cualquier\n",
    "columna y te diga qué tienes delante."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 6\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. El 68% sobre tres columnas\n",
    "\n",
    "Comprueba en tres columnas qué porcentaje cae dentro de una desviación, y compáralo con el 68,3% que promete la campana."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 7\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 8. Cuando el logaritmo sí endereza\n",
    "\n",
    "Aplica logaritmo al monto y mira si la asimetría se va."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 8\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El 68% que salió 81,6%"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Antes de cerrar, la trampa de este capítulo. La regla es correcta, la cuenta es correcta, y el resultado no cuadra 🔔"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### La trampa\n",
    "\n",
    "Aplicas la regla que todo el mundo sabe: entre la media menos una desviación y la media más una está el 68% de los datos. La usas para poner el rango normal de una venta.\n",
    "\n",
    "```\n",
    "mu, sd = v['monto'].mean(), v['monto'].std()\n",
    "dentro = ((v['monto'] > mu - sd) & (v['monto'] < mu + sd)).mean()\n",
    "\n",
    "print(round(dentro * 100, 1))\n",
    "# 81.8\n",
    "```\n",
    "\n",
    "**¿Qué está mal?** La respuesta está en el cuaderno de soluciones. Míralo tú primero."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "Shapiro suspende unidades con p = 5,2e-16 y la aprueba con p = 0,4422 si le das solo 20 filas. ¿Qué concluyes?\n",
    "\n",
    "a) Que la prueba mide cuánta evidencia tengo, no si los datos son normales\n",
    "\n",
    "b) Que con 20 filas la columna sí es normal y con 3.000 deja de serlo\n",
    "\n",
    "c) Que la prueba de Shapiro está mal implementada\n",
    "\n",
    "d) Que hay que usar siempre muestras de 20 para estas pruebas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que te llevas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 👀 El histograma decide más que cualquier prueba. Diez líneas de texto y ya\n",
    "sabías que `monto` no era una campana.\n",
    "\n",
    "- 📐 Asimetría dice hacia dónde cae la cola; curtosis, si es picuda o plana.\n",
    "Una curtosis de -1,3 en cinco valores es la firma de una uniforme.\n",
    "\n",
    "- 🎭 Las pruebas de normalidad no contestan lo que crees. Los mismos datos dan\n",
    "p = 0,44 con 50 filas y p = 0,000000 con 1.000.\n",
    "\n",
    "- 🧭 La pregunta útil no es \"¿es normal?\" sino \"¿cuánto me cuesta suponer que\n",
    "lo es?\". En unidades el error de cuantiles era de una décima; en monto, la normal\n",
    "se inventaba ventas de -433 soles.\n",
    "\n",
    "- 🪄 El logaritmo endereza colas por la derecha: la asimetría del monto pasó\n",
    "de 1,4278 a -0,1585. Pero cuesta 21 filas y complica la interpretación.\n",
    "\n",
    "- 📏 Estandarizar no normaliza. La z deja media 0 y desviación 1, y la\n",
    "asimetría intacta.\n",
    "\n",
    "Y si de todo el capítulo te llevas una sola frase, que sea esta:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La campana no es cómo son los datos. Es una suposición, y se comprueba."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y para mirar la forma de tus datos sin escribir código, un histograma en un\n",
    "tablero hace exactamente el mismo trabajo:\n",
    "[guía de Power BI](https://missyera.com/guias/power-bi-desde-cero/) 📈"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Qué viene ahora"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Han salido tres veces ya: las ventas negativas y las de cuatro mil soles. En\n",
    "el capítulo 6 vamos a por ellas, con las tres formas de detectarlas y la\n",
    "pregunta que casi nadie hace, que es si hay que quitarlas o no 🎯"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Preguntas frecuentes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "¿Qué es un histograma?Un gráfico de barras pegadas donde cada barra cuenta cuántos datos caen dentro de un rango. Sirve para ver de un vistazo la forma que tienen tus datos: si están centrados, si tienen cola, si hay dos grupos escondidos.\n",
    "\n",
    "¿Cómo se hace un histograma?Se parte el rango de los datos en intervalos del mismo ancho, se cuenta cuántos datos caen en cada uno y se dibuja una barra por intervalo. Lo único que hay que elegir es cuántos intervalos, y esa decisión cambia lo que ves.\n",
    "\n",
    "¿Qué diferencia hay entre un histograma y un gráfico de barras?Las barras del histograma van pegadas porque el eje es continuo: representan tramos de un número. Las de un gráfico de barras van separadas porque son categorías sueltas, como canal o ciudad.\n",
    "\n",
    "¿Qué es un histograma de frecuencias?Es el mismo histograma llamado por su nombre completo: la altura de cada barra es la frecuencia, o sea cuántas veces aparece un valor dentro de ese tramo.\n",
    "\n",
    "¿Qué es la campana de Gauss?El nombre coloquial de la distribución normal, por la forma que tiene su histograma: simétrica, con casi todo en el medio y colas que se van apagando a los lados.\n",
    "\n",
    "¿Cómo sé si mis datos son normales?Mirando el histograma primero y con la prueba de Shapiro Wilk después. Y ojo con lo que contesta la prueba: con muchos datos casi siempre dice que no, y eso no significa que no te sirvan.\n",
    "\n",
    "¿Cómo se hace un histograma en Excel?Seleccionas los datos, Insertar, gráficos estadísticos, histograma. Excel elige los intervalos solo, y eso es justo lo que conviene revisar a mano: cambiar el ancho cambia la forma que ves."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 5 de **Estadística desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/estadistica-desde-cero/la-campana/\n",
    "\n",
    "Que tengas lindo día! 🌸"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
