{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Todo el trabajo es decidir qué no cuentas\n",
    "\n",
    "De 42.518 celdas sale una frase. Cómo se elige qué corte enseñas, cuál te callas y cuál no te puedes callar.\n",
    "\n",
    "Cuaderno de soluciones del capítulo 20 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/que-dejas-fuera/\n",
    "\n",
    "Este es el cuaderno de **soluciones**. Trae el código de cada ejercicio, la\n",
    "explicación de la trampa y la respuesta del quiz. Si vienes del cuaderno de\n",
    "práctica sin haberlo intentado, vuelve 🙂"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El capítulo anterior fue cómo se dice. Este es qué se dice, que es más\n",
    "difícil 🌸"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## La proporción, para que veas el tamaño del descarte"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "URL = 'https://missyera.com/static/datasets/ventas-miss-yera.csv'\n",
    "df = pd.read_csv(URL)\n",
    "d = df[['canal', 'compro', 'segmento', 'ciudad']].dropna(subset=['canal', 'compro'])\n",
    "sub = d[d['canal'].isin(['WhatsApp', 'Web'])]\n",
    "\n",
    "print('celdas del archivo:', df.size)\n",
    "print('filas que uso     :', len(sub))\n",
    "print('numeros del titular:', 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "42.518 celdas para decir cuatro números. **Analizar es sobre todo\n",
    "descartar**, y nadie te enseña con qué criterio."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El general, y lo que esconde"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w = sub[sub['canal'] == 'WhatsApp']['compro']\n",
    "b = sub[sub['canal'] == 'Web']['compro']\n",
    "print('diferencia general:', round(float(w.mean() - b.mean()), 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "6,9 puntos. Ese es el titular del capítulo 19.\n",
    "Ahora ábrelo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for seg in sorted(sub['segmento'].dropna().unique()):\n",
    "    s = sub[sub['segmento'] == seg]\n",
    "    a = s[s['canal'] == 'WhatsApp']['compro']\n",
    "    c = s[s['canal'] == 'Web']['compro']\n",
    "    print(seg.ljust(11), 'WhatsApp', round(float(a.mean()), 3),\n",
    "          '| Web', round(float(c.mean()), 3),\n",
    "          '| dif', round(float(a.mean() - c.mean()), 3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mira la distancia: **Minimarket sube 12,3 puntos y Horeca 1,6**.\n",
    "Casi ocho veces.\n",
    "\n",
    "El 6,9 general no está mal calculado, es un promedio correcto. Lo que pasa es\n",
    "que **cambia la recomendación**: con el general, mueves a todos los\n",
    "clientes a WhatsApp. Con la apertura, no mueves a Horeca, porque el esfuerzo no\n",
    "se va a pagar ahí.\n",
    "\n",
    "Ese es el criterio entero de este capítulo: **se enseña lo que cambia\n",
    "la decisión**. No lo que es interesante, no lo que costó trabajo, no lo\n",
    "que quedó bonito."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Y entonces por qué no enseñar todos los cortes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La tentación obvia: si abrir por segmento sirvió, abro por todo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "segs = sub['segmento'].nunique()\n",
    "ciu = sub['ciudad'].nunique()\n",
    "print('segmentos:', segs, '| ciudades:', ciu)\n",
    "print('comparaciones posibles:', segs + ciu + segs * ciu)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "49 comparaciones con dos columnas. Con cinco columnas son cientos.\n",
    "\n",
    "Y con 49 comparaciones, **alguna va a salir significativa por\n",
    "casualidad**. Es el p-hacking del capítulo 17,\n",
    "y no deja de serlo porque tú no lo estuvieras buscando a propósito.\n",
    "\n",
    "La diferencia entre abrir por segmento y hacer p-hacking no está en el\n",
    "código: está en **cuándo lo decidiste**. Si el corte lo elegiste\n",
    "antes de mirar, porque el negocio funciona distinto en cada segmento, es\n",
    "análisis. Si lo elegiste después, porque ese era el que daba, es otra cosa.\n",
    "\n",
    "Por eso la lista de cortes que vas a mirar se escribe antes, igual que el\n",
    "criterio de la prueba A/B del capítulo 18."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## La tabla que nadie lee"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = sub.pivot_table(index='segmento', columns='canal',\n",
    "                    values='compro', aggfunc='mean').round(3)\n",
    "print(t.to_string())\n",
    "print('celdas:', t.size)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ocho celdas, que ya es una tabla chiquita, y aun así nadie la va a leer en\n",
    "una reunión: van a mirar los números buscando el suyo.\n",
    "\n",
    "Lo que sí se lee es la frase que sale de ahí:\n",
    "\n",
    "*\"Minimarket es donde más sube, doce puntos. Horeca casi no se mueve, así\n",
    "que ahí no lo movería.\"*\n",
    "\n",
    "La tabla va igual, en la lámina o en el anexo, porque quien quiera verificar\n",
    "tiene derecho. Pero la tabla **acompaña** a la frase, no la\n",
    "sustituye 🧾"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que no te puedes callar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hasta acá hablamos de elegir. Hay una categoría aparte: lo que se dice\n",
    "aunque estropee tu titular.\n",
    "\n",
    "- **La limitación que cambiaría la conclusión.** Si las filas no\n",
    "son independientes, si el periodo fue raro, si un segmento tiene 30 filas.\n",
    "\n",
    "- **El corte que te salió en contra.** Si abriste por ciudad y\n",
    "en dos no funciona, eso se dice. Callarlo es lo que hace que la próxima vez no\n",
    "te crean.\n",
    "\n",
    "- **Que es correlación y no causa**, cuando no hubo asignación\n",
    "al azar.\n",
    "\n",
    "- **De dónde salieron los supuestos** del cálculo de dinero.\n",
    "\n",
    "La regla que uso: si alguien lo descubriera **después** de\n",
    "decidir, ¿se sentiría engañado? Si la respuesta es sí, va dentro 💛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El error de cortar hasta que no quede nada"
   ]
  },
  {
   "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",
    "    sub[sub['ciudad'] == 'Tarapoto']['compro'].value_counts(normalize=True).loc[1]\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",
    "KeyError: 1\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Un `KeyError` pelado, que no dice nada de lo que pasó de verdad:\n",
    "en Tarapoto no hay ninguna venta, así que no hay nada que contar y no existe la\n",
    "clave.\n",
    "\n",
    "Este error sale cuando encadenas filtros buscando el corte que dé bonito. Y\n",
    "la versión peligrosa es la que **no** revienta: te quedan cuatro\n",
    "filas, sale un 75% espectacular, y ese número acaba en una lámina sin el\n",
    "`n = 4` al lado.\n",
    "\n",
    "La costumbre que lo evita: **imprimir el tamaño del grupo junto al\n",
    "porcentaje, siempre**. No hay excepciones para esa regla."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que te llevas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- De 42.518 celdas salen cuatro números. Analizar es descartar.\n",
    "\n",
    "- Se enseña lo que cambia la decisión.\n",
    "\n",
    "- El promedio general puede ser correcto y esconder lo que importa.\n",
    "\n",
    "- Elegir el corte después de ver los resultados es p-hacking.\n",
    "\n",
    "- La tabla acompaña la frase, no la sustituye.\n",
    "\n",
    "- Lo que se calla se elige; la limitación que cambiaría la conclusión no se\n",
    "elige, va dentro.\n",
    "\n",
    "- El porcentaje sin el tamaño del grupo al lado es medio dato."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "El promedio general dice +6,9 puntos, pero por segmento va de +1,6 en Horeca a +12,3 en Minimarket. ¿Qué llevas a la reunión?\n",
    "\n",
    "a) El general y la apertura por segmento, porque cambian la recomendación: Horeca no se mueve\n",
    "\n",
    "b) Solo el general, porque es el resultado del análisis\n",
    "\n",
    "c) Solo la apertura, porque el detalle siempre es mejor\n",
    "\n",
    "d) Las 49 comparaciones posibles, para que decidan ellos\n",
    "\n",
    "---\n",
    "\n",
    "**La correcta es la a.**\n",
    "\n",
    "*b)* Es el resultado y esconde que un segmento entero casi no responde. Si alguien decide mover a Horeca por tu número, decidió mal con tu número.\n",
    "\n",
    "*c)* Cuatro cifras sueltas sin el total dejan a quien escucha armando el promedio en la cabeza, y lo va a armar mal.\n",
    "\n",
    "*d)* Eso no es transparencia, es traspasar el trabajo. Y con 49 cortes alguna sale significativa por casualidad, que es el p-hacking del capítulo de errores.\n",
    "\n",
    "Se calla lo que no cambia la decisión. Lo que la cambia se dice, aunque estropee el titular 🌸"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Siempre el n al lado del porcentaje\n",
    "\n",
    "Mira cuánto cambia la lectura cuando aparece el tamaño."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for ciudad in sorted(sub['ciudad'].dropna().unique()):\n",
    "    s = sub[sub['ciudad'] == ciudad]['compro']\n",
    "    print(ciudad.ljust(10), 'convierte', round(float(s.mean()), 3),\n",
    "          '| n =', len(s))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "Arequipa   convierte 0.613 | n = 284\n",
    "Chiclayo   convierte 0.59 | n = 244\n",
    "Cusco      convierte 0.635 | n = 244\n",
    "LIMA       convierte 0.667 | n = 66\n",
    "Lima       convierte 0.545 | n = 55\n",
    "Líma       convierte 0.597 | n = 67\n",
    "Piura      convierte 0.624 | n = 263\n",
    "Trujillo   convierte 0.631 | n = 244\n",
    "lima       convierte 0.593 | n = 59\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dos cosas, y las dos importan.\n",
    "\n",
    "La primera: hay **cuatro maneras de escribir Lima** y cada una\n",
    "tiene su fila. Juntas suman 247 ventas, más que cualquier otra ciudad, y\n",
    "separadas parecen cuatro sitios chiquitos. Ese es el trabajo de limpieza que va\n",
    "antes de cualquier informe.\n",
    "\n",
    "La segunda: sin el `n` al lado, las nueve líneas parecen igual de\n",
    "sólidas. Con el `n`, se ve que ese 66,7% de \"LIMA\" sale de 66\n",
    "ventas."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. El corte que te sale en contra\n",
    "\n",
    "Búscalo a propósito, porque es el que hay que contar."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for seg in sorted(sub['segmento'].dropna().unique()):\n",
    "    s = sub[sub['segmento'] == seg]\n",
    "    a = s[s['canal'] == 'WhatsApp']['compro']\n",
    "    c = s[s['canal'] == 'Web']['compro']\n",
    "    dif = float(a.mean() - c.mean())\n",
    "    se = float(np.sqrt(a.var(ddof=1) / len(a) + c.var(ddof=1) / len(c)))\n",
    "    cruza = (dif - 1.96 * se) < 0 < (dif + 1.96 * se)\n",
    "    print(seg.ljust(11), 'dif', round(dif, 3),\n",
    "          '| intervalo cruza el cero:', cruza)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "Bodega      dif 0.063 | intervalo cruza el cero: True\n",
    "Horeca      dif 0.016 | intervalo cruza el cero: True\n",
    "Mayorista   dif 0.075 | intervalo cruza el cero: True\n",
    "Minimarket  dif 0.123 | intervalo cruza el cero: False\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tres de los cuatro cruzan el cero. Solo Minimarket se sostiene.\n",
    "\n",
    "O sea que de la apertura entera, lo único que puedes afirmar es\n",
    "**\"en Minimarket sube y en los otros tres no lo sabemos\"**. Bodega\n",
    "y Mayorista tienen una dirección que apunta bien y una muestra que no alcanza\n",
    "para probarla, porque al abrir cada grupo se queda con unas 180 filas y el\n",
    "intervalo se ensancha, como viste en el capítulo\n",
    "19.\n",
    "\n",
    "Fíjate en lo cómodo que sería callarse esta línea y presentar los cuatro\n",
    "números como si los cuatro dijeran algo. Y fíjate en lo distinto que suena el\n",
    "informe honesto: no es peor, es más útil, porque le dice a quien decide dónde\n",
    "poner el esfuerzo primero 💛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Cuántas comparaciones hacen falta para encontrar algo\n",
    "\n",
    "La cuenta que explica el p-hacking sin fórmulas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for k in (1, 5, 20, 49):\n",
    "    p = 1 - 0.95 ** k\n",
    "    print('con', str(k).rjust(2), 'comparaciones, probabilidad de al menos un',\n",
    "          'falso positivo:', round(p * 100, 1), '%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "con  1 comparaciones, probabilidad de al menos un falso positivo: 5.0 %\n",
    "con  5 comparaciones, probabilidad de al menos un falso positivo: 22.6 %\n",
    "con 20 comparaciones, probabilidad de al menos un falso positivo: 64.2 %\n",
    "con 49 comparaciones, probabilidad de al menos un falso positivo: 91.9 %\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Con las 49 comparaciones que tenía a mano, la probabilidad de que\n",
    "**al menos una salga significativa siendo mentira es del 91,9%**.\n",
    "\n",
    "Por eso no es una cuestión de honestidad personal: aunque no estés haciendo\n",
    "trampa, si miras cuarenta y nueve cortes vas a encontrar uno. La defensa es\n",
    "decidir los cortes antes, y decir cuántos miraste."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. El resumen de una línea, generado\n",
    "\n",
    "Que la frase salga del dato y no de tu memoria."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "filas = []\n",
    "for seg in sorted(sub['segmento'].dropna().unique()):\n",
    "    s = sub[sub['segmento'] == seg]\n",
    "    a = s[s['canal'] == 'WhatsApp']['compro']\n",
    "    c = s[s['canal'] == 'Web']['compro']\n",
    "    filas.append((float(a.mean() - c.mean()), seg))\n",
    "filas.sort(reverse=True)\n",
    "mejor, peor = filas[0], filas[-1]\n",
    "print('El mayor efecto esta en', mejor[1], 'con',\n",
    "      round(mejor[0] * 100, 1), 'puntos.')\n",
    "print('El menor esta en', peor[1], 'con', round(peor[0] * 100, 1), 'puntos.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "El mayor efecto esta en Minimarket con 12.3 puntos.\n",
    "El menor esta en Horeca con 1.6 puntos.\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dos líneas que se pegan al informe tal cual. La gracia no es ahorrarse\n",
    "escribir: es que si mañana entran datos nuevos y Horeca pasa a ser el mejor, la\n",
    "frase cambia sola y tú te enteras."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. La limitación, medida en vez de intuida\n",
    "\n",
    "Cuenta cuántos grupos tienen menos de 100 filas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chicos = []\n",
    "for seg in sorted(sub['segmento'].dropna().unique()):\n",
    "    for ciudad in sorted(sub['ciudad'].dropna().unique()):\n",
    "        n = len(sub[(sub['segmento'] == seg) & (sub['ciudad'] == ciudad)])\n",
    "        if n < 100:\n",
    "            chicos.append(n)\n",
    "print('cruces segmento por ciudad:', 4 * 9)\n",
    "print('con menos de 100 filas    :', len(chicos))\n",
    "print('el mas chico              :', min(chicos))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "cruces segmento por ciudad: 36\n",
    "con menos de 100 filas    : 36\n",
    "el mas chico              : 10\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Los 36 cruces tienen menos de 100 filas y el más chico tiene 10. Esa frase,\n",
    "tal cual, es la limitación que va en el informe: \"no abro por segmento y ciudad\n",
    "a la vez porque el cruce más chico tiene diez ventas\".\n",
    "\n",
    "Decirlo medido es muy distinto de decir \"no había suficientes datos\". Lo\n",
    "primero es un análisis; lo segundo suena a excusa."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. La prueba del engaño\n",
    "\n",
    "Aplica la regla a tres cosas que podrías callarte."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "casos = [\n",
    "    ('use una prueba t de Welch y no de Student', False),\n",
    "    ('los cuatro intervalos por segmento cruzan el cero', True),\n",
    "    ('tarde tres dias en limpiar las ciudades', False),\n",
    "    ('los clientes se repiten entre filas', True),\n",
    "]\n",
    "for texto, va_dentro in casos:\n",
    "    print(('VA DENTRO ' if va_dentro else 'se puede omitir'), texto)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "se puede omitir use una prueba t de Welch y no de Student\n",
    "VA DENTRO  los cuatro intervalos por segmento cruzan el cero\n",
    "se puede omitir tarde tres dias en limpiar las ciudades\n",
    "VA DENTRO  los clientes se repiten entre filas\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Las dos que van dentro tienen algo en común: si alguien las descubriera\n",
    "después de decidir, se sentiría engañado. Las otras dos son trabajo tuyo, y el\n",
    "trabajo tuyo va en el anexo o no va.\n",
    "\n",
    "Esa es la prueba entera, y se puede aplicar en diez segundos antes de mandar\n",
    "cualquier informe 💛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 20 de **Estadística desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/estadistica-desde-cero/que-dejas-fuera/\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
}
