{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Una prueba A/B de principio a fin\n",
    "\n",
    "El orden en que se hace: primero cuántos hacen falta, después el reparto, y el resultado al final. Y el 17,7% que cuesta mirar antes de tiempo.\n",
    "\n",
    "Cuaderno de práctica del capítulo 18 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/una-prueba-ab-de-verdad/\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": [
    "Diecisiete capítulos de piezas sueltas. Este las monta todas en el orden en\n",
    "que se usan de verdad, sobre la pregunta que más se hace en una empresa:\n",
    "**¿esto que cambiamos sirvió?** 🧪\n",
    "\n",
    "Y te aviso desde ya: lo que hace que una prueba A/B valga o no valga se decide\n",
    "casi todo **antes de empezar**. Cuando ya tienes los datos, lo que\n",
    "queda es una cuenta de tres líneas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\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).dropna(subset=['compro'])\n",
    "BASE = v['compro'].mean()\n",
    "\n",
    "print('clientes: %d' % len(v))\n",
    "print('conversion de hoy: %.4f' % BASE)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ese 0,5777 es el punto de partida, y a partir de él ya se puede contestar la\n",
    "pregunta que casi nadie hace 🐣"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Paso 1, y es el que se salta todo el mundo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Antes de tocar nada: **¿cuánta gente hace falta para poder ver el cambio\n",
    "que espero?** Si la respuesta es más de la que tienes, el experimento no\n",
    "se hace, porque ya sabes que va a salir \"no concluyente\" pase lo que pase."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cuantos_hacen_falta(p1, p2, potencia=0.80, alfa=0.05):\n",
    "    \"\"\"Cuantos por grupo para ver un cambio de p1 a p2.\"\"\"\n",
    "    z_a = stats.norm.ppf(1 - alfa / 2)\n",
    "    z_b = stats.norm.ppf(potencia)\n",
    "    p = (p1 + p2) / 2\n",
    "    return int(np.ceil(2 * p * (1 - p) * (z_a + z_b) ** 2 / (p2 - p1) ** 2))\n",
    "\n",
    "\n",
    "print('conversion de hoy: %.4f' % BASE)\n",
    "for mejora in [0.01, 0.02, 0.03, 0.05, 0.10]:\n",
    "    n = cuantos_hacen_falta(BASE, BASE + mejora)\n",
    "    print('  para ver +%.0f puntos: %6d por grupo' % (mejora * 100, n))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahí está la conversación entera que hay que tener con quien pide el\n",
    "experimento 💼\n",
    "\n",
    "Para ver una mejora de un punto hacen falta **38.172 personas por\n",
    "grupo**, o sea 76.344 en total. Y nosotros tenemos 3.000. Se acabó: ese\n",
    "experimento no se puede hacer aquí, y saberlo hoy vale más que descubrirlo en\n",
    "tres meses.\n",
    "\n",
    "Con 1.500 por grupo solo alcanza para ver cambios de **cinco puntos para\n",
    "arriba**. Así que el experimento solo tiene sentido si de verdad esperas\n",
    "un cambio grande. Fíjate además en la forma de la tabla: bajar de 5 puntos a 1\n",
    "multiplica por veinticinco la gente que necesitas, porque el efecto entra al\n",
    "cuadrado en el denominador. Eso ya salió en el capítulo\n",
    "14, y aquí es lo que decide si hay proyecto o no."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Paso 2, repartir de verdad al azar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahora el reparto. Y una cosa que parece de perogrullo y no lo es: se reparte\n",
    "**al azar**, no por ciudad, ni por vendedor, ni por quien conteste\n",
    "primero. Si el reparto no es al azar, lo que midas después mezcla tu cambio con\n",
    "lo que diferencie a los grupos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "generador = np.random.default_rng(7)\n",
    "lado = generador.permutation(len(v)) % 2\n",
    "v = v.assign(grupo=np.where(lado == 0, 'A', 'B'))\n",
    "\n",
    "print('a cada grupo le tocaron:')\n",
    "print(v['grupo'].value_counts().to_string())\n",
    "print()\n",
    "print('y comprobamos que los grupos salieron parecidos:')\n",
    "print(pd.crosstab(v['grupo'], v['segmento'], normalize='index').round(3).to_string())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esa segunda tabla es la comprobación de equilibrio, y hay que hacerla siempre\n",
    "📋\n",
    "\n",
    "Los repartos están cerca pero no son idénticos: el grupo B se llevó un 26,1%\n",
    "de mayoristas contra el 23,9% de A. Eso es normal y es el azar haciendo su\n",
    "trabajo. Lo que buscas no es que sean iguales, es que no haya una diferencia\n",
    "gorda que después te explique el resultado.\n",
    "\n",
    "Y esto conecta directo con el capítulo 9: allí\n",
    "el problema era quién entra en la muestra, y aquí es quién cae en cada lado. Es\n",
    "el mismo peligro dos veces."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Paso 3, el resultado"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hasta aquí no hemos cambiado nada. Los dos grupos reciben exactamente lo mismo,\n",
    "porque quiero enseñarte primero lo que tiene que salir cuando no hay nada:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = v[v['grupo'] == 'A']['compro']\n",
    "b = v[v['grupo'] == 'B']['compro']\n",
    "print('grupo A: %d personas, convierte %.4f' % (len(a), a.mean()))\n",
    "print('grupo B: %d personas, convierte %.4f' % (len(b), b.mean()))\n",
    "print('diferencia: %+.4f' % (b.mean() - a.mean()))\n",
    "\n",
    "tabla = np.array([[a.sum(), len(a) - a.sum()], [b.sum(), len(b) - b.sum()]])\n",
    "print('valor p: %.4f' % stats.chi2_contingency(tabla)[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Siete diezmilésimas de diferencia y un valor p de 1,0000 💚\n",
    "\n",
    "Eso es exactamente lo que tenía que salir, porque **no cambiamos\n",
    "nada**. Y esto tiene nombre: es una **prueba A/A**, y es lo\n",
    "primero que se corre antes de cualquier A/B de verdad.\n",
    "\n",
    "Suena a perder el tiempo y es lo contrario. Si tu A/A sale significativa, no\n",
    "has descubierto nada: tienes rota la tubería. El reparto no es al azar, o los\n",
    "grupos se contaminan, o estás contando dos veces al mismo cliente. Correrla\n",
    "cuesta una tarde y te ahorra creerte un hallazgo que era un fallo de plomería 🔧"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Paso 4, y ahora con un cambio de verdad"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Vamos a fabricar un efecto real de cinco puntos y ver si la máquina lo caza:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def experimento(efecto, semilla):\n",
    "    \"\"\"Reparte al azar y le suma `efecto` a la conversion del grupo B.\"\"\"\n",
    "    g = np.random.default_rng(semilla)\n",
    "    lado = g.permutation(len(v)) % 2\n",
    "    base = v['compro'].values.copy()\n",
    "    empujados = (lado == 1) & (base == 0) & (g.random(len(v)) < efecto / (1 - BASE))\n",
    "    base = np.where(empujados, 1, base)\n",
    "    return base[lado == 0], base[lado == 1]\n",
    "\n",
    "\n",
    "a5, b5 = experimento(0.05, 7)\n",
    "print('grupo A convierte %.4f' % a5.mean())\n",
    "print('grupo B convierte %.4f' % b5.mean())\n",
    "t = np.array([[a5.sum(), len(a5) - a5.sum()], [b5.sum(), len(b5) - b5.sum()]])\n",
    "print('valor p: %.6f' % stats.chi2_contingency(t)[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lo caza 🎯\n",
    "\n",
    "Cinco puntos de mejora y un valor p de 0,004. Y no es suerte: la tabla del\n",
    "paso 1 decía que con 1.504 por grupo se ven los cambios de cinco puntos, y\n",
    "tenemos 1.500. El experimento estaba **diseñado** para poder ver\n",
    "esto, y por eso lo ve."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Y ahora el pecado, que es el que de verdad cuesta dinero"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tienes el experimento corriendo. Van tres días. Y miras. Y al día siguiente\n",
    "miras otra vez. Y el jueves sale p = 0,03 y lo paras y lo anuncias 🎉\n",
    "\n",
    "Vamos a medir cuánto cuesta eso. Trescientos experimentos donde\n",
    "**no hay ningún efecto**, comparando mirar solo al final contra\n",
    "mirar cada cien personas y parar al primer resultado bonito:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mira_pronto(efecto, semilla, cada=100):\n",
    "    \"\"\"Corre el experimento y va mirando el valor p cada `cada` personas.\"\"\"\n",
    "    a, b = experimento(efecto, semilla)\n",
    "    for n in range(cada, len(a) + 1, cada):\n",
    "        ta = np.array([[a[:n].sum(), n - a[:n].sum()],\n",
    "                       [b[:n].sum(), n - b[:n].sum()]])\n",
    "        if ta.min() == 0:\n",
    "            continue\n",
    "        if stats.chi2_contingency(ta)[1] < 0.05:\n",
    "            return True\n",
    "    return False\n",
    "\n",
    "\n",
    "sin_efecto = sum(mira_pronto(0.0, s) for s in range(300))\n",
    "print('de 300 experimentos donde NO hay ningun efecto real:')\n",
    "print('  mirando solo al final, lo esperado es el 5.0%')\n",
    "print('  mirando cada 100 personas y parando al primer p<0.05: %.1f%%'\n",
    "      % (sin_efecto / 300 * 100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Del 5% al 17,7% 😱\n",
    "\n",
    "Uno de cada seis experimentos **sin ningún efecto** te va a dar un\n",
    "resultado significativo en algún momento del camino, si te dedicas a mirar. Y lo\n",
    "vas a parar justo ahí, porque es cuando la noticia es buena.\n",
    "\n",
    "No hace falta mala fe. Basta con querer saber cómo va. El valor p del capítulo\n",
    "12 promete un 5% de falsas alarmas **si miras una\n",
    "vez**, y cada vistazo extra es una oportunidad más de que el azar te\n",
    "sonría."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El tamaño de la muestra y la fecha de parada se escriben antes de empezar. Todo lo que se decida después de ver los datos ya no es un experimento."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Los dos errores, y el peor es el que no revienta"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Empiezo por el que sí revienta, y es bonito porque la que se queja es la\n",
    "aritmética:"
   ]
  },
  {
   "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",
    "    cuantos_hacen_falta(BASE, BASE)\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",
    "OverflowError: cannot convert float infinity to integer\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Le preguntaste cuánta gente hace falta para detectar una mejora de cero, y la\n",
    "respuesta es **infinita**. Tiene todo el sentido: una diferencia que\n",
    "no existe no se detecta nunca, por mucha gente que metas. La división entre cero\n",
    "del denominador es esa frase escrita en números 🔑\n",
    "\n",
    "Y ahora el que no revienta, que es el que te va a morder de verdad.\n",
    "`chi2_contingency` quiere **cuántos**, no **qué\n",
    "proporción**. Si le pasas las tasas de conversión en vez de los conteos:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "stats.chi2_contingency(np.array([[0.5780, 0.4220],\n",
    "                                 [0.6300, 0.3700]]))\n",
    "# devuelve p = 1.0000, sin una sola queja\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Un valor p perfectamente formado, perfectamente inútil y perfectamente\n",
    "silencioso. Con proporciones la prueba cree que tienes **un cliente por\n",
    "grupo** en vez de mil quinientos, así que no encuentra nada nunca.\n",
    "\n",
    "La comprobación cabe en una línea y hay que hacerla siempre:\n",
    "`tabla.sum()` tiene que darte el número de personas del experimento.\n",
    "Si te da 2, la tabla está en proporciones 🚩"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## La receta entera, para tenerla a mano"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| Cuándo | Qué se hace | Qué pasa si te lo saltas |\n",
    "|---|---|---|\n",
    "| **Antes** | Escribir la pregunta y qué mejora valdría la pena | Al final se elige la métrica que salió bien |\n",
    "| **Antes** | Calcular cuántos hacen falta, y cancelar si no los tienes | Tres meses para un \"no concluyente\" que ya se sabía |\n",
    "| **Antes** | Fijar la fecha de parada | El 17,7% de arriba |\n",
    "| **Al empezar** | Repartir al azar y correr una A/A | Se confunde el cambio con lo que ya diferenciaba a los grupos |\n",
    "| **Al empezar** | Comprobar que los grupos quedaron parecidos | Un desequilibrio gordo explica el resultado y nadie lo mira |\n",
    "| **Al final** | Una prueba, un intervalo y el tamaño del efecto | Se reporta un valor p solo, que no dice si importa |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cuatro de las seis filas son de antes de empezar, y eso es lo que quiero que\n",
    "te lleves de este capítulo 🗓️\n",
    "\n",
    "Si quieres leer más, la guía de experimentos de\n",
    "[exp-platform](https://exp-platform.com/), que es el equipo que montó la\n",
    "experimentación en Microsoft, tiene los casos reales de todo lo que sale mal, y\n",
    "son mucho más raros de lo que uno se imagina 📄"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### La trampa\n",
    "\n",
    "Una tienda prueba un botón nuevo. A la semana el equipo reporta que el grupo B convierte más y que el valor p es 0,012, y lo lanzan a todos.\n",
    "\n",
    "```\n",
    "# lunes\n",
    "print(prueba(a[:400], b[:400]))     # p = 0.31, seguimos\n",
    "# miercoles\n",
    "print(prueba(a[:900], b[:900]))     # p = 0.18, seguimos\n",
    "# viernes\n",
    "print(prueba(a[:1500], b[:1500]))   # p = 0.012  y lo paramos aqui\n",
    "```\n",
    "\n",
    "**¿Qué está mal?** La respuesta está en el cuaderno de soluciones. Míralo tú primero."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Seis. El 2 es el que te va a servir mañana en una reunión 💛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Corre tu propia A/A\n",
    "\n",
    "Reparte al azar veinte veces sin cambiar nada y cuenta\n",
    "cuántas salen significativas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. La calculadora de antes de empezar\n",
    "\n",
    "Con la conversión de tu negocio, haz la tabla de cuánta\n",
    "gente necesitas para cada mejora."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Cuánto cuesta mirar más seguido\n",
    "\n",
    "Repite la medición del 17,7% mirando cada 50, cada 100 y\n",
    "cada 300 personas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Ponle intervalo a la diferencia\n",
    "\n",
    "Con el bootstrap del capítulo\n",
    "11, dale un intervalo a la diferencia entre A y B."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. El efecto que no alcanzas a ver\n",
    "\n",
    "Fabrica un efecto real de dos puntos y mira si la prueba lo\n",
    "detecta."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. Mira si el efecto es igual en todos los segmentos\n",
    "\n",
    "Parte el resultado por `segmento` y mira si el\n",
    "cambio ayuda a todos por igual."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. Lo que cuestan la potencia y el alfa\n",
    "\n",
    "Deja fijos los tres puntos de mejora y mueve la potencia y el alfa. Arma la tabla del precio de cada combinación."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 8. La potencia, comprobada a mano\n",
    "\n",
    "Corre el experimento doscientas veces con tres efectos distintos y cuenta cuántas veces sale significativo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "Tu experimento lleva cuatro días de los diez planeados y ya sale p = 0,04. ¿Qué haces?\n",
    "\n",
    "a) Lo dejas correr hasta el día diez, como estaba escrito\n",
    "\n",
    "b) Lo paras y lo lanzas, que ya salió\n",
    "\n",
    "c) Lo paras y corres otro para confirmar\n",
    "\n",
    "d) Sigues y a partir de ahora miras todos los días"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que te llevas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 🗓️ Cuatro de los seis pasos son antes de empezar. Lo de después son tres\n",
    "líneas.\n",
    "\n",
    "- 🔢 Para ver +1 punto sobre una conversión de 0,5777 hacen falta 38.172 por\n",
    "grupo. Con 3.000 clientes ese experimento no se puede hacer, y saberlo hoy vale\n",
    "más que descubrirlo en tres meses.\n",
    "\n",
    "- 🔁 La prueba A/A va primero: si sale significativa sin cambiar nada, lo roto\n",
    "es la tubería.\n",
    "\n",
    "- 👀 Mirar cada cien personas y parar en el primer resultado bonito sube los\n",
    "falsos hallazgos del 5% al 17,7%.\n",
    "\n",
    "- 📉 Y un \"no significativo\" con muestra chica no dice que el cambio no\n",
    "sirva.\n",
    "\n",
    "El capítulo 19 hace este mismo recorrido sobre una\n",
    "pregunta de negocio entera y termina en un informe de una página. Y el\n",
    "vocabulario suelto está en el [glosario de IA](https://missyera.com/glosario-ia/) 📖\n",
    "\n",
    "Que tengas lindo día! 🌸"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 18 de **Estadística desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/estadistica-desde-cero/una-prueba-ab-de-verdad/\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
}
