{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# El contrato de datos\n",
    "\n",
    "Las cuatro preguntas que deciden si el proyecto sirve, y las cuatro tienen respuesta medible en el archivo.\n",
    "\n",
    "Cuaderno de práctica del capítulo 2 de **Machine learning 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/machine-learning-desde-cero/el-contrato-de-datos/\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",
    "    1: \"Y291bnQgICAgNjE3LjAwCm1lYW4gICAgICAgNC45MgpzdGQgICAgICAgIDIuMjQKbWluICAgICAgICAxLjAwCjI1JSAgICAgICAgMy4wMAo1MCUgICAgICAgIDUuMDAKNzUlICAgICAgICA2LjAwCm1heCAgICAgICAxNC4wMApOYW1lOiBjb3VudCwgZHR5cGU6IGZsb2F0NjQ=\",\n",
    "    2: \"dGFzYTogMC4xOTA2CnBvc2l0aXZvczogNTc5\",\n",
    "    3: \"VHJ1ZQ==\",\n",
    "    5: \"S2V5RXJyb3I6ICdjbGllbnRlJw==\",\n",
    "    6: \"b3BvcnR1bmlkYWRlczogMzAzNwpjYXBhY2lkYWQgc2VtYW5hbDogMjAwCnBvcmNlbnRhamUgYXRlbmRpYmxlOiA2LjY=\",\n",
    "    8: \"Y3XDoW50b3Mgc29uICAgICAgOiAyMQpxdcOpICUgZGUgbGFzIGZpbGFzOiAwLjcwJQpjdcOhbnRvIHN1bWFuICAgICA6IC04OTU0LjA0CnZhbG9yZXMgZGUgY29tcHJvOiBbbnAuaW50NjQoMCld\",\n",
    "    9: \"ZGVzY3VlbnRvICBtaW46IDAuMCAgbWF4OiAwLjI1ICBudWxvczogMTkuOCUKdW5pZGFkZXMgICBtaW46IDEgIG1heDogMzA=\",\n",
    "    10: \"aHVlY29zIGVuIHNhdGlzZmFjY2nDs246IDM5LjAlCgogIC0gbW9udG86IG3DrW5pbW8gLTI0OTcuNzIsIGVsIGNvbnRyYXRvIGRpY2UgMAogIC0gc2F0aXNmYWNjaW9uOiAzOS4wJSBkZSBodWVjb3MsIGVsIHRvcGUgZXMgMTAl\",\n",
    "}, lenguaje=\"python\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Este es el capítulo que casi ningún curso enseña y el que decide si el\n",
    "proyecto sirve o no sirve 💛\n",
    "\n",
    "Y antes de nada, una pregunta para ti: **¿cuál fue el último informe que hiciste y que nadie usó para decidir nada?** Piénsalo, porque casi siempre no falló el análisis. Faltó esta conversación 💭\n",
    "\n",
    "Va antes del código a propósito, porque todo lo que viene después depende de\n",
    "él. Y no es teoría de consultora: son cuatro preguntas concretas que hay que\n",
    "hacer, y las cuatro tienen respuesta medible en el archivo.\n",
    "\n",
    "La escena de siempre: \"Yera, queremos un modelo que prediga qué clientes van\n",
    "a comprar\". Suena clarísimo y no lo es. Vamos a ver por qué."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pregunta 1. ¿Qué se va a hacer distinto?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Antes que nada, esta. Si la respuesta es \"tener el dato\", el proyecto no\n",
    "empieza.\n",
    "\n",
    "Un modelo no sirve para saber: sirve para **decidir distinto**.\n",
    "Y esa decisión tiene que existir antes de que exista el modelo.\n",
    "\n",
    "- ✅ \"Vamos a llamar a los 200 clientes con más probabilidad de comprar.\"\n",
    "Perfecto: hay una acción, un número de llamadas y alguien que las hace.\n",
    "\n",
    "- ✅ \"Vamos a darle 10% de descuento a los que están a punto de irse.\"\n",
    "Perfecto también, y encima define el costo de equivocarse.\n",
    "\n",
    "- ❌ \"Queremos entender mejor a nuestros clientes.\" Eso no es un modelo, es un\n",
    "análisis, y es más barato y más útil. Capítulo 14 del\n",
    "[libro de SQL](https://missyera.com/guias/sql-desde-cero/).\n",
    "\n",
    "- ❌ \"Para el directorio.\" Ese proyecto muere en tres meses, y lo digo con\n",
    "cariño 🫠\n",
    "\n",
    "De esa respuesta salen dos cosas que vas a necesitar sí o sí: **cuántas\n",
    "predicciones se pueden atender** (si el call center hace 200 llamadas,\n",
    "tu lista tiene 200 nombres, no 3.000) y **cuánto cuesta cada tipo de\n",
    "error**. Las dos vuelven en el capítulo 15."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pregunta 2. ¿Una fila es qué, exactamente?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Aquí es donde se cae la mitad de los proyectos, y se ve en un número."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "URL = 'https://missyera.com/static/datasets/ventas-miss-yera.csv'\n",
    "ventas = pd.read_csv(URL)\n",
    "\n",
    "print('filas:', len(ventas))\n",
    "print('clientes distintos:', ventas['cliente_id'].nunique())\n",
    "print('tasa por venta:', round(ventas['compro'].mean(), 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "3.037 ventas de 617 clientes, y el 57,7% de las ventas se cierra.\n",
    "\n",
    "Ahora la misma pregunta mirando clientes en vez de ventas:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "por_cliente = ventas.groupby('cliente_id')['compro'].max()\n",
    "print('clientes que compraron alguna vez:', round(por_cliente.mean(), 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**93%.** Contra el 57,7% de antes.\n",
    "\n",
    "Los dos números son correctos y contestan preguntas distintas. \"¿Se cierra\n",
    "esta venta?\" es 57,7%. \"¿Este cliente compra alguna vez?\" es 93%. Si el cliente\n",
    "te pide lo segundo y tú entrenas lo primero, entregas un modelo impecable que no\n",
    "sirve 😳\n",
    "\n",
    "Y hay un tercer corte, que suele ser el que de verdad quieren:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tasa = ventas.groupby('cliente_id')['compro'].mean()\n",
    "print('clientes que compran siempre:', round((tasa == 1).mean(), 4))\n",
    "print('clientes que no compran nunca:', round((tasa == 0).mean(), 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Solo el 11,8% compra siempre y el 7% no compra nunca. O sea que\n",
    "**el 81% de los clientes a veces sí y a veces no**, y esos son los\n",
    "interesantes: los que dependen de algo que puedes cambiar.\n",
    "\n",
    "La pregunta que hay que hacer en la reunión, palabra por palabra:\n",
    "*¿una fila de tu reporte es una venta o es un cliente?* 🎯"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pregunta 3. ¿Qué significa exactamente la etiqueta?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\"Compró\" parece que no necesita definición. Sí la necesita.\n",
    "\n",
    "¿Compró si pagó? ¿Si le llegó el pedido? ¿Y si devolvió? ¿Y si compró\n",
    "S/12 cuando el mínimo rentable son S/300?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "monto = pd.to_numeric(ventas['monto'].str.replace(',', '.'), errors='coerce')\n",
    "venta_grande = ((ventas['compro'] == 1) & (monto > 500)).astype(int)\n",
    "\n",
    "print('objetivo \"cerró\":        ', round(ventas['compro'].mean(), 4))\n",
    "print('objetivo \"cerró y > 500\":', round(venta_grande.mean(), 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "57,7% contra 35,2%. **Es el mismo archivo y son dos problemas\n",
    "distintos**, con distinto listón, distinta dificultad y distinto valor\n",
    "para el negocio.\n",
    "\n",
    "Y fíjate en que la segunda definición es más útil casi siempre: al call\n",
    "center no le sirve saber que alguien va a comprar un chicle 🍬\n",
    "\n",
    "La definición del objetivo se escribe, se firma y se pega arriba del cuaderno.\n",
    "Cambiarla a mitad de proyecto significa tirar todo lo medido."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pregunta 4. ¿En qué momento se predice?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esta es la que más caro sale y la que nadie hace. Se llama el\n",
    "**momento de la predicción**: qué se sabe y qué no se sabe cuando\n",
    "el modelo tiene que contestar.\n",
    "\n",
    "Mira esta columna del archivo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(ventas.groupby('compro')['monto_final_facturado'].agg(['count', 'min', 'max', 'mean']).round(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Todas las ventas que no se cerraron tienen exactamente 0,00. Todas las que sí,\n",
    "tienen un monto.\n",
    "\n",
    "O sea que esa columna **es la respuesta escrita de otra forma**.\n",
    "Un modelo que la use va a acertar el 100%, y va a fallar el 100% en producción,\n",
    "porque el día que tienes que predecir todavía no se facturó nada.\n",
    "\n",
    "Eso se llama **fuga de información** y tiene el capítulo 12\n",
    "entero, con la demostración numérica. Aquí me interesa la parte que no es\n",
    "técnica: **se caza preguntando, no programando**. Por cada columna\n",
    "de tu tabla, una pregunta:\n",
    "\n",
    "*Esto, ¿cuándo se rellena?*\n",
    "\n",
    "Si la respuesta es \"cuando se cierra la venta\", fuera. Si es \"el mes\n",
    "siguiente\", fuera. Si es \"cuando el cliente reclama\", fuera. Y ojo, que las\n",
    "peores no se llaman `monto_final_facturado`: se llaman\n",
    "`score_riesgo` o `segmento_asignado` y las calculó otro\n",
    "equipo con información que tú no ves 🕵️‍♀️"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El contrato, en una tabla"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esto es lo que yo pego arriba del cuaderno antes de escribir una línea:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| Punto | Ejemplo con este archivo |\n",
    "|---|---|\n",
    "| **Decisión** | Qué llamadas hace el equipo comercial esta semana |\n",
    "| **Capacidad** | 200 llamadas por semana, o sea 200 nombres |\n",
    "| **Unidad** | Una fila es una oportunidad de venta |\n",
    "| **Objetivo** | `compro = 1`, o sea que se cerró |\n",
    "| **Momento** | Al registrarse la oportunidad, antes de gestionarla |\n",
    "| **Prohibido** | `monto_final_facturado`: solo existe después |\n",
    "| **Costo de fallar** | Llamar de más: 15 minutos. No llamar a quien iba a comprar: la venta entera |\n",
    "| **Listón** | 57,7% de cierre sin modelo |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ocho líneas. Escribirlas cuesta una reunión de cuarenta minutos y evita el\n",
    "mes que se pierde cuando alguien dice \"ah, pero yo pensaba que era por\n",
    "cliente\" 📋"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El otro contrato: el de las columnas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y hay una parte más aburrida que también hay que acordar, porque si no un\n",
    "lunes te llega el archivo con las columnas renombradas y todo revienta."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(ventas.dtypes)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahí ya hay dos avisos: `monto` es texto cuando debería ser un\n",
    "número (viene con coma decimal), y `fecha` también es texto. Los dos\n",
    "son el capítulo 4.\n",
    "\n",
    "Lo que se acuerda con quien manda los datos: **los nombres de las\n",
    "columnas, su tipo, sus valores posibles y qué significa un hueco**. Esa\n",
    "última es la que más se olvida y la que más vale, y por eso tiene su propia\n",
    "sección en el capítulo 4 🕳️"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Un contrato que no se pueda comprobar no es un contrato"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Todo lo de arriba está escrito en prosa, y la prosa se pudre. Dentro de seis\n",
    "meses nadie va a releer esa tabla antes de correr el cuaderno 📄\n",
    "\n",
    "Así que el contrato se escribe en código, y se comprueba solo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "CONTRATO = {\n",
    "    'id_venta':     {'tipo': 'int64',   'nulos': 0.0,  'unico': True},\n",
    "    'cliente_id':   {'tipo': 'str',     'nulos': 0.0,  'unico': False},\n",
    "    'monto':        {'tipo': 'float64', 'nulos': 0.05, 'min': 0},\n",
    "    'unidades':     {'tipo': 'int64',   'nulos': 0.0,  'min': 1},\n",
    "    'satisfaccion': {'tipo': 'float64', 'nulos': 0.10, 'min': 1, 'max': 5},\n",
    "    'compro':       {'tipo': 'int64',   'nulos': 0.0,  'valores': {0, 1}},\n",
    "}\n",
    "\n",
    "print(len(CONTRATO), 'columnas con reglas')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cada regla es una frase de la tabla de arriba, escrita de forma que una\n",
    "máquina la pueda revisar. \"El monto nunca es negativo\" se convierte en\n",
    "`'min': 0`. \"Como mucho un 10% de satisfacciones sin contestar\" se\n",
    "convierte en `'nulos': 0.10` 🔒\n",
    "\n",
    "Y ahora la función que las revisa. Es más corta de lo que parece:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def revisa(tabla, contrato):\n",
    "    problemas = []\n",
    "    for col, regla in contrato.items():\n",
    "        if col not in tabla.columns:\n",
    "            problemas.append(f'{col}: no está en la tabla')\n",
    "            continue\n",
    "        s = tabla[col]\n",
    "        if str(s.dtype) != regla['tipo']:\n",
    "            problemas.append(f'{col}: es {s.dtype} y el contrato dice {regla[\"tipo\"]}')\n",
    "        hueco = s.isna().mean()\n",
    "        if hueco > regla['nulos']:\n",
    "            problemas.append(f'{col}: {hueco:.1%} de huecos, el tope es {regla[\"nulos\"]:.0%}')\n",
    "        if regla.get('unico') and s.duplicated().any():\n",
    "            problemas.append(f'{col}: hay {s.duplicated().sum()} repetidos y debería ser único')\n",
    "        # Solo si de verdad es numérica. Un validador que revienta al mirar una\n",
    "        # columna rota no sirve: se cae justo cuando hace falta.\n",
    "        numerica = pd.api.types.is_numeric_dtype(s)\n",
    "        if 'min' in regla and numerica and s.min() < regla['min']:\n",
    "            problemas.append(f'{col}: mínimo {s.min()}, el contrato dice {regla[\"min\"]}')\n",
    "        if 'max' in regla and numerica and s.max() > regla['max']:\n",
    "            problemas.append(f'{col}: máximo {s.max()}, el contrato dice {regla[\"max\"]}')\n",
    "        if 'valores' in regla and not set(s.dropna().unique()) <= regla['valores']:\n",
    "            problemas.append(f'{col}: valores fuera de {regla[\"valores\"]}')\n",
    "    return problemas\n",
    "\n",
    "\n",
    "fallos = revisa(ventas, CONTRATO)\n",
    "print(len(fallos), 'incumplimientos')\n",
    "for f in fallos:\n",
    "    print('  -', f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dos, y los dos son de verdad 🔍\n",
    "\n",
    "**37 id_venta repetidos.** El contrato decía que una fila es una\n",
    "venta y que `id_venta` la identifica. Si se repite 37 veces, o hay\n",
    "duplicados o una fila no es lo que creíamos. Las dos posibilidades hay que\n",
    "resolverlas antes de entrenar nada.\n",
    "\n",
    "**El monto es texto.** Ya lo sabíamos, pero fíjate en que no\n",
    "hizo falta que nadie se acordara: la comprobación lo dijo sola.\n",
    "\n",
    "Y una decisión de diseño que parece un detalle: esa línea de\n",
    "`numerica`. Sin ella, la función revienta al intentar comparar el\n",
    "monto de texto con cero, y se cae **antes** de contarte los otros\n",
    "problemas. Un validador tiene que aguantar los datos rotos, porque los datos\n",
    "rotos son su único trabajo 🛡️"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que el contrato encuentra después de limpiar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahora la parte interesante. Arreglamos los dos problemas y volvemos a\n",
    "pasarlo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "limpias = ventas.drop_duplicates(subset='id_venta').copy()\n",
    "limpias['monto'] = pd.to_numeric(limpias['monto'].astype(str).str.replace(',', '.'),\n",
    "                                 errors='coerce')\n",
    "\n",
    "for f in revisa(limpias, CONTRATO):\n",
    "    print('  -', f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Aparece uno que antes estaba escondido: **hay un monto de\n",
    "-2.497,72** 😳\n",
    "\n",
    "Estaba ahí desde el principio, pero no se podía ver: mientras la columna era\n",
    "texto, la regla del mínimo ni se comprobaba. Limpiar un problema destapó otro,\n",
    "y eso pasa constantemente.\n",
    "\n",
    "De ahí sale la costumbre que quiero que te lleves: **el contrato se\n",
    "vuelve a pasar después de cada limpieza**, no una vez al principio. Cada\n",
    "arreglo cambia lo que se puede comprobar.\n",
    "\n",
    "¿Y qué se hace con ese monto negativo? Depende de qué sea, y eso no lo dicen\n",
    "los datos. Puede ser una devolución mal registrada, un ajuste contable o un\n",
    "dedazo. Preguntar cuál de las tres es exactamente el trabajo de este capítulo:\n",
    "el contrato no es un filtro, es **una lista de preguntas para quien conoce\n",
    "el negocio** 💬"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dónde vive esta comprobación"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tres sitios, y los tres a la vez 📍\n",
    "\n",
    "- 🧪 **Al cargar los datos, en el cuaderno.** Si el archivo de\n",
    "este mes viene distinto, te enteras en la primera celda y no en la quinta hora.\n",
    "\n",
    "- 🚦 **Antes de entrenar.** Un modelo entrenado sobre datos que\n",
    "incumplen el contrato es un modelo que no se puede defender.\n",
    "\n",
    "- 🌙 **En producción, con los datos que llegan.** Y ahí no para\n",
    "el proceso: avisa. De eso va el capítulo 27.\n",
    "\n",
    "Lo importante es que sea **el mismo código en los tres**. Un\n",
    "contrato que se comprueba de una forma en el cuaderno y de otra en producción es\n",
    "dos contratos, y el día que no cuadren vas a tardar semanas en descubrir cuál de\n",
    "los dos mentía 🌀"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Siete. Intenta antes de abrir 💛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Cuántas oportunidades tiene cada cliente\n",
    "\n",
    "Distribución de filas por cliente: mínimo, mediana y\n",
    "máximo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 1\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. El objetivo, definido en soles\n",
    "\n",
    "Cuánto cambia el listón si el objetivo es \"cerró y pasa de\n",
    "S/1.000\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 2\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. La columna prohibida, en una línea\n",
    "\n",
    "Demuestra que `monto_final_facturado` es la\n",
    "respuesta disfrazada."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 3\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Qué se sabe antes y qué después\n",
    "\n",
    "Clasifica las 14 columnas del archivo según si se conocen\n",
    "antes de gestionar la venta o no."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. El error que te va a pasar en la primera reunión\n",
    "\n",
    "El cliente te dice \"agrupa por cliente\" y tú escribes lo\n",
    "que suena."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 5\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. Cuántas llamadas caben\n",
    "\n",
    "Si el equipo hace 200 llamadas por semana y hay 3.037\n",
    "oportunidades, ¿qué porcentaje de la lista puedes atender?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 6\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. El contrato de tu propio proyecto\n",
    "\n",
    "Copia esta plantilla y llénala con un caso tuyo, aunque sea\n",
    "inventado. Es el ejercicio que más te va a servir de todo el capítulo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 8. El negativo, de cerca\n",
    "\n",
    "Antes de preguntar nada, mira quiénes son."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 8\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9. Las columnas que el contrato no vigila\n",
    "\n",
    "Mira dos que no metí en el contrato y decide si deberían\n",
    "estar."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 9\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 10. El archivo del mes que viene\n",
    "\n",
    "Simula un archivo con más huecos de la cuenta y comprueba\n",
    "que el contrato lo pilla."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 10\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "¿Cuándo se decide qué significa cada columna?\n",
    "\n",
    "a) Antes de tocar el modelo, y por escrito\n",
    "\n",
    "b) Cuando el modelo dé resultados raros\n",
    "\n",
    "c) Lo decide quien programa, mirando los datos\n",
    "\n",
    "d) No hace falta si el modelo funciona"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Y ahora la que se cuela por el hueco de la pregunta 4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### La trampa\n",
    "\n",
    "Te pasan este script \"que ya da 100%\". El código corre, la columna existe y el número es real. Mira de dónde sale esa columna antes de seguir.\n",
    "\n",
    "```\n",
    "X = ventas.drop(columns=['compro'])\n",
    "X['facturo'] = (ventas['monto_final_facturado']\n",
    "                > 0).astype(int)\n",
    "\n",
    "# ...y el modelo acierta el 100%\n",
    "```\n",
    "\n",
    "**¿Qué está mal?** La respuesta está en el cuaderno de soluciones. Míralo tú primero."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que te llevas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 🎬 Si nadie va a hacer nada distinto con la predicción, no hay proyecto.\n",
    "\n",
    "- 🧱 La unidad manda: aquí, 57,7% por venta contra 93% por cliente. Son dos\n",
    "preguntas y solo una es la que te pidieron.\n",
    "\n",
    "- 🏷️ El objetivo se define por escrito: \"cerró\" da 57,7% y \"cerró y pasa de\n",
    "S/500\" da 35,2%.\n",
    "\n",
    "- ⏰ El momento de la predicción es lo que caza la fuga, y se caza\n",
    "preguntando por cada columna cuándo se rellena.\n",
    "\n",
    "- 🚫 `monto_final_facturado` convertida a \"mayor que cero\" es\n",
    "idéntica al objetivo en las 3.037 filas. Fuera.\n",
    "\n",
    "- 📞 La capacidad cambia la métrica: con 200 llamadas para 3.037\n",
    "oportunidades, lo que importa es el orden, no el acierto global.\n",
    "\n",
    "- 📋 Ocho líneas de contrato cuestan una reunión y ahorran un mes.\n",
    "\n",
    "Y si de todo el capítulo te llevas una sola frase, que sea esta:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Un proyecto de datos no empieza con datos. Empieza con la decisión que va a cambiar."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "En el capítulo 4 abrimos el archivo de verdad y nos peleamos con la suciedad:\n",
    "Lima escrita de cuatro formas, montos con coma, fechas en dos formatos y tres\n",
    "columnas con huecos.\n",
    "\n",
    "Que tengas lindo día! 🌸"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 2 de **Machine learning desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/machine-learning-desde-cero/el-contrato-de-datos/\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
}
