{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Las seis preguntas que te van a hacer\n",
    "\n",
    "Cada pregunta de una reunión tiene una cuenta detrás. Llevarlas hechas es la diferencia entre defender tu análisis y volver la semana que viene.\n",
    "\n",
    "Cuaderno de soluciones del capítulo 21 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/las-preguntas-de-la-reunion/\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": [
    "Ya tienes el titular y ya elegiste qué mostrar. Ahora te van a preguntar.\n",
    "\n",
    "Y la buena noticia es que las preguntas son casi siempre las mismas seis. La\n",
    "mala es que cada una necesita una cuenta que no está en tu cuaderno todavía 🌸"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from math import ceil\n",
    "\n",
    "URL = 'https://missyera.com/static/datasets/ventas-miss-yera.csv'\n",
    "df = pd.read_csv(URL)\n",
    "df['monto'] = pd.to_numeric(df['monto'], errors='coerce')\n",
    "d = df[['canal', 'compro', 'segmento', 'ciudad', 'monto']].dropna(\n",
    "    subset=['canal', 'compro'])\n",
    "sub = d[d['canal'].isin(['WhatsApp', 'Web'])]\n",
    "\n",
    "w = sub[sub['canal'] == 'WhatsApp']['compro']\n",
    "b = sub[sub['canal'] == 'Web']['compro']\n",
    "dif = float(w.mean() - b.mean())\n",
    "se = float(np.sqrt(w.var(ddof=1) / len(w) + b.var(ddof=1) / len(b)))\n",
    "print('diferencia:', round(dif, 4), '| error estandar:', round(se, 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. \"¿Y qué tan seguro estás?\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('entre', round((dif - 1.96 * se) * 100, 1), 'y',\n",
    "      round((dif + 1.96 * se) * 100, 1), 'puntos')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Es la pregunta más frecuente y la más fácil, porque ya la contestaste en el\n",
    "capítulo 10.\n",
    "\n",
    "Lo que hay que resistir es la tentación de contestar \"el p-valor es 0,0053\".\n",
    "Nadie sabe qué hacer con eso. **\"Entre 2 y 12 puntos\"** lo entiende\n",
    "todo el mundo y dice exactamente lo mismo, con la ventaja de que trae el tamaño\n",
    "dentro 🧾"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. \"¿Y si no hacemos nada?\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('la web ya convierte:', round(float(b.mean()), 4))\n",
    "print('con 1.000 clientes ya compran', round(float(b.mean()) * 1000))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esta es la que más análisis hunde, y casi nadie la lleva preparada.\n",
    "\n",
    "La web ya convierte 583 de cada 1.000. Tu propuesta no trae 652 ventas\n",
    "nuevas: trae **69 más de las que ya había**. Sin la línea base al\n",
    "lado, el número grande parece todo el mérito del proyecto.\n",
    "\n",
    "Se llama **línea base** y es la respuesta a \"¿comparado con\n",
    "qué?\". Cuando alguien te presente una mejora sin decirte la suya, esa es la\n",
    "pregunta que hay que hacer."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. \"¿Cuánta plata es?\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ticket = float(d['monto'].dropna().mean())\n",
    "print('centro    :', round(dif * 1000 * ticket), 'soles')\n",
    "print('borde bajo:', round((dif - 1.96 * se) * 1000 * ticket), 'soles')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Los dos números, siempre. Si llevas solo el 56.086, alguien va a poner eso en\n",
    "un presupuesto y tú vas a ser la responsable de que no llegue.\n",
    "\n",
    "Y la frase que hay que decir en voz alta: *\"esto asume 1.000 clientes y el\n",
    "ticket medio actual, y las dos cosas pueden cambiar\"*."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. \"¿Funciona para todos?\""
   ]
  },
  {
   "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), 'dif', round(float(a.mean() - c.mean()), 3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "No. Horeca casi no se mueve, y eso es lo que trabajamos en el capítulo\n",
    "20.\n",
    "\n",
    "Si esta pregunta te la hacen y no la tienes hecha, la reunión se acaba ahí:\n",
    "\"vuelve cuando lo hayas abierto\"."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. \"¿Te alcanzó la muestra?\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esta la hacen poco y es la que más duele cuando llega:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def muestra_necesaria(p1, p2):\n",
    "    pb = (p1 + p2) / 2\n",
    "    return ceil((1.96 * np.sqrt(2 * pb * (1 - pb))\n",
    "                 + 0.84 * np.sqrt(p1 * (1 - p1) + p2 * (1 - p2))) ** 2\n",
    "                / (p1 - p2) ** 2)\n",
    "\n",
    "n = muestra_necesaria(float(w.mean()), float(b.mean()))\n",
    "print('hacian falta por grupo:', n)\n",
    "print('tengo                 :', len(w), 'y', len(b))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "768 hacían falta, y en WhatsApp tengo **725**. Me quedé corta en\n",
    "uno de los dos grupos.\n",
    "\n",
    "Esto no invalida el análisis: la diferencia salió significativa igual. Lo que\n",
    "dice es que estaba justo en el límite, y que si el efecto hubiera sido un poco\n",
    "más chico, no lo habría visto. Es exactamente la advertencia del capítulo\n",
    "18, y decirla tú antes de que la pregunten vale\n",
    "mucho."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. \"¿Esto es causa o solo pasa que...?\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La pregunta difícil, y la única que no se contesta con una cuenta."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mezcla = sub.groupby('canal')['segmento'].value_counts(normalize=True).round(3)\n",
    "print(mezcla.to_string())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Los dos canales tienen prácticamente la misma mezcla de segmentos, entre 24%\n",
    "y 27% cada uno. O sea que el segmento **no** explica la\n",
    "diferencia.\n",
    "\n",
    "Y aun así la respuesta correcta es: **no lo sé**. Porque el canal\n",
    "lo eligió el cliente, no yo. Puede que quien usa WhatsApp ya venga con más ganas\n",
    "de comprar, y eso no lo mide ninguna de mis columnas.\n",
    "\n",
    "Lo que sí puedo decir es qué haría falta para saberlo: repartir clientes al\n",
    "azar entre los dos canales, que es la prueba A/B del capítulo\n",
    "18. Sin eso, es correlación, y llamarla causa es lo\n",
    "que trabajamos en el capítulo 15."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Y cuando el resultado no es el que querían"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Pasa, y es el momento donde más se nota quién sabe hacer esto.\n",
    "\n",
    "Lo que no funciona: suavizarlo, buscar el corte que sí dio, o decir \"hay una\n",
    "tendencia\" cuando el intervalo cruza el cero.\n",
    "\n",
    "Lo que funciona son tres frases, en este orden:\n",
    "\n",
    "- **El resultado, sin adornos.** \"No encontramos diferencia.\"\n",
    "\n",
    "- **Qué descarta.** \"Con esta muestra podríamos haber visto\n",
    "diferencias de 7 puntos o más, así que si existe algo, es menor que eso.\" Eso es\n",
    "información y vale dinero.\n",
    "\n",
    "- **Qué harías ahora.** \"Con este presupuesto yo probaría otra\n",
    "cosa antes que insistir acá.\"\n",
    "\n",
    "Un no medido es un resultado. Un no disfrazado de sí es un problema que\n",
    "aparece seis meses después, cuando ya nadie se acuerda de tu lámina 💛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que te llevas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Las seis preguntas son casi siempre las mismas: certeza, línea base,\n",
    "dinero, segmentos, muestra y causa.\n",
    "\n",
    "- El intervalo se dice en puntos, no en p-valor.\n",
    "\n",
    "- Sin línea base, cualquier mejora parece más grande de lo que es.\n",
    "\n",
    "- El dinero va con su borde bajo y con sus supuestos dichos.\n",
    "\n",
    "- La muestra necesaria se calcula, y decir que te quedaste corta te da\n",
    "crédito.\n",
    "\n",
    "- La causa la da el diseño, no la prueba.\n",
    "\n",
    "- Un resultado negativo se presenta con lo que descarta y con qué harías\n",
    "ahora."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "Presentas que WhatsApp sube 6,9 puntos y alguien pregunta \"¿y eso es causa o solo pasa que los mejores clientes usan WhatsApp?\". ¿Qué contestas?\n",
    "\n",
    "a) Que el canal lo eligió el cliente, así que es correlación, y qué haría falta para saberlo\n",
    "\n",
    "b) Que el valor p de 0,0053 demuestra que es causa\n",
    "\n",
    "c) Que sí, porque comprobé que los segmentos están parejos\n",
    "\n",
    "d) Que con más datos se sabría\n",
    "\n",
    "---\n",
    "\n",
    "**La correcta es la a.**\n",
    "\n",
    "*b)* El valor p dice que la diferencia no es casualidad del muestreo. De dónde viene la diferencia no lo dice ninguna prueba, lo dice cómo se repartieron los grupos.\n",
    "\n",
    "*c)* Comprobar que un factor no confunde es buena señal y no cierra la pregunta: quedan todos los factores que no mediste.\n",
    "\n",
    "*d)* Más datos del mismo tipo dan el mismo problema con un intervalo más estrecho. Lo que falta no es cantidad, es asignación al azar.\n",
    "\n",
    "La pregunta de la causa no se contesta con estadística, se contesta con el diseño. Y si no hubo diseño, se dice 🧾"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Cuánta muestra para ver diferencias más chicas\n",
    "\n",
    "La cuenta que hay que hacer antes de empezar, no después."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "base = float(b.mean())\n",
    "for efecto in (0.07, 0.05, 0.03, 0.01):\n",
    "    n = muestra_necesaria(base + efecto, base)\n",
    "    print('para ver', round(efecto * 100, 1), 'puntos hacen falta',\n",
    "          n, 'por grupo')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "para ver 7.0 puntos hacen falta 755 por grupo\n",
    "para ver 5.0 puntos hacen falta 1494 por grupo\n",
    "para ver 3.0 puntos hacen falta 4187 por grupo\n",
    "para ver 1.0 puntos hacen falta 37984 por grupo\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Para ver un punto hacen falta casi 38.000 por grupo. Cuando alguien te pida\n",
    "\"medir si el cambio del botón mejora algo\", esta tabla es la que te dice si es\n",
    "posible con el tráfico que tienen. Casi siempre no lo es, y saberlo antes ahorra\n",
    "un trimestre."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. El error de pedir certeza sobre nada\n",
    "\n",
    "Pregúntale a la fórmula cuánta muestra hace falta para\n",
    "detectar una diferencia de cero."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "muestra_necesaria(0.60, 0.60)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "OverflowError: cannot convert float infinity to integer\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Infinita. Y no es un capricho de la fórmula: **no existe una muestra\n",
    "que te permita demostrar que dos cosas son exactamente iguales**.\n",
    "\n",
    "Por eso \"no encontramos diferencia\" nunca quiere decir \"son iguales\". Lo que\n",
    "se puede decir es lo del punto 2 de arriba: cuál es la diferencia más chica que\n",
    "habrías podido ver."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Qué descarta tu no\n",
    "\n",
    "Convierte un resultado negativo en información."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "n_real = min(len(w), len(b))\n",
    "for efecto in (0.10, 0.07, 0.05, 0.03):\n",
    "    hace_falta = muestra_necesaria(float(b.mean()) + efecto, float(b.mean()))\n",
    "    print('efecto de', round(efecto * 100), 'puntos ->',\n",
    "          'lo habria visto' if hace_falta <= n_real else 'no me alcanzaba')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "efecto de 10 puntos -> lo habria visto\n",
    "efecto de 7 puntos -> no me alcanzaba\n",
    "efecto de 5 puntos -> no me alcanzaba\n",
    "efecto de 3 puntos -> no me alcanzaba\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esa es la frase entera: *\"si hubiera un efecto de 10 puntos o más lo habría\n",
    "visto; de 7 para abajo, con esta muestra no puedo decir nada\"*.\n",
    "\n",
    "Y fíjate en lo justo que quedó: 7 puntos necesitaban 755 por grupo y tengo\n",
    "725. Por treinta filas. El efecto que encontré, 6,9 puntos, está exactamente en\n",
    "esa zona donde la muestra no daba garantías, y salió igual. Tuve suerte, y eso\n",
    "también se dice.\n",
    "\n",
    "Convertir un no en un límite superior es lo que hace que un resultado\n",
    "negativo sirva para decidir en vez de tirarse a la basura."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. La línea base que nadie te dio\n",
    "\n",
    "Compara la mejora contra lo que ya pasaba, no contra cero."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "base = float(b.mean())\n",
    "print('sin hacer nada, de cada 1000:', round(base * 1000))\n",
    "print('con el cambio, de cada 1000 :', round(float(w.mean()) * 1000))\n",
    "print('ventas nuevas               :', round(dif * 1000))\n",
    "print('la mejora es el', round(dif / float(w.mean()) * 100, 1),\n",
    "      '% de lo que se atribuye el proyecto')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "sin hacer nada, de cada 1000: 583\n",
    "con el cambio, de cada 1000 : 652\n",
    "ventas nuevas               : 69\n",
    "la mejora es el 10.6 % de lo que se atribuye el proyecto\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "De las 652 ventas que el proyecto va a poder mostrar como suyas, 583 iban a\n",
    "pasar igual. Solo el 10,6% es mérito del cambio. Esa cuenta es la que evita que\n",
    "un proyecto se cuelgue medallas ajenas, y sirve para leer las de otros."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. Comprueba si un factor te está confundiendo\n",
    "\n",
    "El chequeo del punto 6, hecho función."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mezcla_pareja(datos, factor, grupo='canal', tolerancia=0.05):\n",
    "    t = datos.groupby(grupo)[factor].value_counts(normalize=True).unstack()\n",
    "    brecha = float((t.max() - t.min()).max())\n",
    "    return round(brecha, 4), brecha < tolerancia\n",
    "\n",
    "print('segmento:', mezcla_pareja(sub, 'segmento'))\n",
    "print('ciudad  :', mezcla_pareja(sub, 'ciudad'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "segmento: (0.0247, True)\n",
    "ciudad  : (0.0129, True)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Las dos brechas son menores de 5 puntos, así que ni el segmento ni la ciudad\n",
    "están repartidos de forma que expliquen la diferencia. Es una buena señal y\n",
    "**no** es una prueba de causa: solo descarta dos sospechosos de los\n",
    "que sí mediste."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. La hoja de respuestas, generada\n",
    "\n",
    "Las seis, calculadas de una vez, para llevar impresas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ticket = float(d['monto'].dropna().mean())\n",
    "respuestas = [\n",
    "    ('certeza', 'entre ' + str(round((dif - 1.96 * se) * 100, 1)) + ' y '\n",
    "                + str(round((dif + 1.96 * se) * 100, 1)) + ' puntos'),\n",
    "    ('linea base', str(round(float(b.mean()) * 1000)) + ' de cada 1000 ya compran'),\n",
    "    ('dinero', str(round((dif - 1.96 * se) * 1000 * ticket)) + ' a '\n",
    "               + str(round((dif + 1.96 * se) * 1000 * ticket)) + ' soles'),\n",
    "    ('segmentos', 'Horeca casi no se mueve'),\n",
    "    ('muestra', 'hacian falta 768 por grupo, tengo ' + str(len(w))),\n",
    "    ('causa', 'el canal lo eligio el cliente, es correlacion'),\n",
    "]\n",
    "for pregunta, respuesta in respuestas:\n",
    "    print(pregunta.ljust(11), respuesta)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "certeza     entre 2.1 y 11.8 puntos\n",
    "linea base  583 de cada 1000 ya compran\n",
    "dinero      16733 a 95439 soles\n",
    "segmentos   Horeca casi no se mueve\n",
    "muestra     hacian falta 768 por grupo, tengo 725\n",
    "causa       el canal lo eligio el cliente, es correlacion\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Seis líneas. Eso es lo que llevo a una reunión debajo de la lámina, y en el\n",
    "90% de los casos no necesito ninguna otra cosa.\n",
    "\n",
    "La costumbre de generarlas con código y no de memoria tiene un motivo\n",
    "concreto: cuando alguien pregunte y tú contestes con el número exacto sin dudar,\n",
    "la conversación cambia de sitio 💛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 21 de **Estadística desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/estadistica-desde-cero/las-preguntas-de-la-reunion/\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
}
