{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Cuándo una red neuronal ayuda y cuándo es un error caro\n",
    "\n",
    "Empezamos midiendo: sobre los datos de este libro la red pierde contra una regresión logística, y pierde más cuanto más grande es.\n",
    "\n",
    "Cuaderno de práctica del capítulo 1 de **Deep 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/deep-learning-desde-cero/cuando-si-y-cuando-no/\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: \"cmVkIGRlIDEgbmV1cm9uYTogMC43MDE5CmxvZ8Otc3RpY2EgICAgICAgOiAwLjcyMTQ=\",\n",
    "    2: \"KDEsKSAgICAgICAgICAgICAgICAgICAgIDMxIHBlc29zICAgICAwLjAxIHBvciBmaWxhCigxNiwpICAgICAgICAgICAgICAgICAgIDQ4MSBwZXNvcyAgICAgMC4yMSBwb3IgZmlsYQooNjQsIDMyKSAgICAgICAgICAgICAgIDM5NjkgcGVzb3MgICAgIDEuNzYgcG9yIGZpbGEKKDEyOCwgNjQsIDMyKSAgICAgICAgIDE0MDgxIHBlc29zICAgICA2LjI2IHBvciBmaWxhCig1MTIsIDI1NiwgMTI4KSAgICAgIDE3OTIwMSBwZXNvcyAgICA3OS42NCBwb3IgZmlsYQ==\",\n",
    "    4: \"bG9nw61zdGljYTogMC40ODY3CnJlZCAgICAgIDogMC45OTk5\",\n",
    "    5: \"bG9nw61zdGljYSBjb24gbG9zIGN1YWRyYWRvczogMS4w\",\n",
    "    6: \"VmFsdWVFcnJvcjogY291bGQgbm90IGNvbnZlcnQgc3RyaW5nIHRvIGZsb2F0OiAnbGltYSc=\",\n",
    "    7: \"ICAgICAgICAgICAgIG1vZGVsbyAgICBBVUMgIHBlc29zCiB0b250byAoc2llbXByZSBzw60pIDAuNTAwMCAgICAgIDAKICAgICAgICAgIGxvZ8Otc3RpY2EgMC43MjE0ICAgICAyOApyZWQgNjQtMzIgY29uIGZyZW5vIDAuNzAxOCAgIDM4NzI=\",\n",
    "}, lenguaje=\"python\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Este es un libro de redes neuronales que empieza diciéndote cuándo no\n",
    "usarlas. Ya sé que es raro 🙃\n",
    "\n",
    "Empiezo preguntándote algo: **¿te han pedido alguna vez \"algo con IA\" sin decirte qué problema resolvía?** Casi todo lo que voy a contarte en este capítulo sale de esa conversación 💭\n",
    "\n",
    "Lo hago por una razón concreta: en los últimos años me han llegado varios\n",
    "proyectos donde alguien montó una red porque sonaba serio, y la respuesta buena\n",
    "eran tres líneas de otra cosa. Eso cuesta meses y credibilidad.\n",
    "\n",
    "Así que antes de la primera neurona, vamos a medirlo sobre los datos de la\n",
    "distribuidora, que son los mismos del libro de machine learning 📊"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El punto de partida"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn.compose import ColumnTransformer\n",
    "from sklearn.impute import SimpleImputer\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.metrics import roc_auc_score\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.neural_network import MLPClassifier\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.preprocessing import OneHotEncoder, StandardScaler\n",
    "\n",
    "URL = 'https://missyera.com/static/datasets/ventas-miss-yera.csv'\n",
    "\n",
    "def carga_limpia(url):\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', errors='coerce')\n",
    "        v[col] = f\n",
    "    return v\n",
    "\n",
    "def prepara(v):\n",
    "    v = v.sort_values(['cliente_id', 'fecha']).copy()\n",
    "    v['sin_compra_previa'] = v['fecha_ultima_compra'].isna().astype(int)\n",
    "    v['sin_descuento'] = v['descuento'].isna().astype(int)\n",
    "    v['sin_satisfaccion'] = v['satisfaccion'].isna().astype(int)\n",
    "    v['precio_unitario'] = v['monto'] / v['unidades']\n",
    "    v['visita_numero'] = v.groupby('cliente_id').cumcount() + 1\n",
    "    return v\n",
    "\n",
    "NUMERICAS = ['unidades', 'monto', 'descuento', 'satisfaccion', 'precio_unitario',\n",
    "             'sin_compra_previa', 'sin_descuento', 'sin_satisfaccion', 'visita_numero']\n",
    "CATEGORICAS = ['ciudad', 'segmento', 'canal', 'categoria']\n",
    "\n",
    "def arma(modelo):\n",
    "    return Pipeline([\n",
    "        ('pre', ColumnTransformer([\n",
    "            ('num', Pipeline([('r', SimpleImputer(strategy='median')),\n",
    "                              ('e', StandardScaler())]), NUMERICAS),\n",
    "            ('cat', Pipeline([('r', SimpleImputer(strategy='most_frequent')),\n",
    "                              ('c', OneHotEncoder(handle_unknown='ignore'))]), CATEGORICAS),\n",
    "        ])),\n",
    "        ('mod', modelo),\n",
    "    ])\n",
    "\n",
    "datos = prepara(carga_limpia(URL))\n",
    "X = datos[NUMERICAS + CATEGORICAS]\n",
    "y = datos['compro']\n",
    "X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.25,\n",
    "                                          random_state=42, stratify=y)\n",
    "print('filas:', len(datos), ' columnas que entran:', X.shape[1])\n",
    "print('compran el:', round(y.mean(), 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ese preprocesamiento es el mismo del capítulo 5 del libro de machine\n",
    "learning. Y el escalado, que allá era una buena práctica, aquí es\n",
    "**obligatorio**: una red con columnas sin escalar no converge, y lo\n",
    "vamos a ver con nuestros ojos en el capítulo 6 🧮"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## La comparación, sin adornos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "competidores = [\n",
    "    ('regresión logística', LogisticRegression(max_iter=1000, random_state=42)),\n",
    "    ('red de 16', MLPClassifier(hidden_layer_sizes=(16,), max_iter=300,\n",
    "                                random_state=42)),\n",
    "    ('red de 64 y 32', MLPClassifier(hidden_layer_sizes=(64, 32), max_iter=300,\n",
    "                                     random_state=42)),\n",
    "]\n",
    "\n",
    "for nombre, modelo in competidores:\n",
    "    m = arma(modelo).fit(X_tr, y_tr)\n",
    "    entrena = roc_auc_score(y_tr, m.predict_proba(X_tr)[:, 1])\n",
    "    prueba = roc_auc_score(y_te, m.predict_proba(X_te)[:, 1])\n",
    "    print(f'{nombre:20} entrena={entrena:.4f}  prueba={prueba:.4f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Léelo columna por columna que hay tres cosas 👀\n",
    "\n",
    "**La red pierde.** 0,7214 la logística contra 0,6584 y 0,5834.\n",
    "Y no por poco: la de dos capas está a diez puntos, que en AUC es un abismo.\n",
    "\n",
    "**Cuanto más grande, peor.** La red de 64 y 32 tiene más de\n",
    "tres mil pesos que ajustar y 2.250 filas para hacerlo. No hay forma.\n",
    "\n",
    "**Y mira la columna de entrenamiento.** 1,0000. Perfecto. La red\n",
    "grande *memorizó las 2.250 filas* y por eso en prueba se hunde 😱\n",
    "\n",
    "Eso último es lo que hay que entender de este capítulo: una red neuronal es\n",
    "una máquina de memorizar, y lo hace tan bien que hay que trabajar para\n",
    "impedírselo. En el capítulo 8 dedicamos el rato entero a eso."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ¿Y si la red está mal configurada?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Es la primera objeción y es justa. Probemos con freno."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "con_freno = [\n",
    "    ('64 y 32, parada temprana', MLPClassifier(hidden_layer_sizes=(64, 32),\n",
    "                                               max_iter=300, early_stopping=True,\n",
    "                                               random_state=42)),\n",
    "    ('16, con penalización', MLPClassifier(hidden_layer_sizes=(16,), max_iter=300,\n",
    "                                           alpha=1.0, random_state=42)),\n",
    "]\n",
    "\n",
    "for nombre, modelo in con_freno:\n",
    "    m = arma(modelo).fit(X_tr, y_tr)\n",
    "    print(f'{nombre:26} entrena={roc_auc_score(y_tr, m.predict_proba(X_tr)[:, 1]):.4f}  '\n",
    "          f'prueba={roc_auc_score(y_te, m.predict_proba(X_te)[:, 1]):.4f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Con freno mejoran muchísimo: de 0,5834 a 0,7018 y a 0,7072. La memorización\n",
    "desaparece, porque el entrenamiento ya no se lleva a la red hasta el fondo.\n",
    "\n",
    "Y aun así **siguen perdiendo** contra las tres líneas de la\n",
    "regresión logística 🤷‍♀️\n",
    "\n",
    "Esto no es un accidente de estos datos. Con datos en tabla y pocas filas,\n",
    "los modelos lineales y los árboles ganan casi siempre, y hay competencias\n",
    "enteras donde el primer puesto es un boosting y las redes quedan atrás."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Entonces, ¿cuándo sí?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cuando los datos tienen una **estructura que las columnas no\n",
    "capturan**. Esa es toda la regla y es más útil que cualquier lista."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| Tipo de dato | La estructura que tiene | Qué usar |\n",
    "|---|---|---|\n",
    "| Tabla (clientes, ventas) | Ninguna. Cambiar el orden de las columnas no cambia nada | Logística, bosques, boosting |\n",
    "| Imágenes | Los píxeles vecinos significan algo juntos | Convolucionales, capítulo 11 |\n",
    "| Texto | El orden importa y hay dependencias largas | Transformers, capítulo 16 |\n",
    "| Audio y series | El tiempo es una dimensión de verdad | Convolucionales 1D, transformers |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hay una frase que se repite mucho en el oficio y que conviene mirar de cerca:\n",
    "**para datos en tabla el boosting le gana a una red casi siempre**.\n",
    "Sobre estos datos, el boosting saca 0,6799 y la red con freno del capítulo 8 saca\n",
    "0,7207, o sea que aquí *no* se cumple.\n",
    "\n",
    "Lo que sí se cumple es lo de fondo: las dos pierden contra la regresión\n",
    "logística, que saca 0,7214. En tabla, los modelos simples mandan, y cuál de los\n",
    "complicados queda segundo cambia de un dataset a otro 🤷‍♀️\n",
    "\n",
    "Fíjate en la primera fila de la tabla, que es la que explica todo lo de\n",
    "arriba. En\n",
    "nuestra tabla, si intercambias la columna `monto` con\n",
    "`ciudad`, no se pierde información. En una foto, si intercambias dos\n",
    "píxeles, la rompes.\n",
    "\n",
    "**Ahí es donde una red gana**: no en tener más capacidad, sino en\n",
    "que su arquitectura ya sabe algo sobre la forma del dato antes de ver el primer\n",
    "ejemplo 💡"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## La otra pregunta: cuántos datos hacen falta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for n in [300, 750, 1500, 2250]:\n",
    "    sub = X_tr.sample(n, random_state=42)\n",
    "    obj = y_tr.loc[sub.index]\n",
    "    log = arma(LogisticRegression(max_iter=1000, random_state=42)).fit(sub, obj)\n",
    "    red = arma(MLPClassifier(hidden_layer_sizes=(64, 32), max_iter=300,\n",
    "                             early_stopping=True, random_state=42)).fit(sub, obj)\n",
    "    print(f'n={n:5d}  logística={roc_auc_score(y_te, log.predict_proba(X_te)[:, 1]):.4f}  '\n",
    "          f'red={roc_auc_score(y_te, red.predict_proba(X_te)[:, 1]):.4f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Con 300 filas la red va ocho puntos por debajo (0,6306 contra 0,7097): no\n",
    "tiene con qué. A partir de 750 se empareja, e incluso le gana por poco en esa\n",
    "fila, y de ahí en adelante van las dos casi pegadas.\n",
    "\n",
    "O sea que la red con freno *sí* alcanza a la logística en cuanto hay\n",
    "datos suficientes, y lo que no consigue es pasarla. Que es el resumen del\n",
    "capítulo: aquí no hay nada más que sacarle a estos datos, y el modelo simple ya\n",
    "lo estaba sacando 📈\n",
    "\n",
    "La respuesta honesta a \"¿cuántos datos necesito?\" sigue siendo: más que el\n",
    "otro modelo. Y los modelos de imágenes que te suenan se entrenaron con millones\n",
    "de ejemplos, no con miles."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Y entonces por qué un libro entero"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Por tres razones que van en serio:\n",
    "\n",
    "- 🖼️ **Porque los datos con forma existen en tu trabajo.**\n",
    "Facturas escaneadas, fotos de anaquel, comentarios de clientes, audios de call\n",
    "center. Nada de eso entra en una tabla.\n",
    "\n",
    "- 🤖 **Porque los LLM son esto.** ChatGPT y Claude son\n",
    "transformers, y entender la atención del capítulo 16 cambia cómo les escribes y\n",
    "qué esperas de ellos.\n",
    "\n",
    "- 🛡️ **Porque te van a vender redes.** Y con este libro vas a\n",
    "poder pedir la comparación contra el modelo simple, que es la pregunta que\n",
    "desarma el 80% de las propuestas infladas.\n",
    "\n",
    "Lo que vamos a hacer aquí es escribir las redes a mano, con numpy, sin\n",
    "librería que las esconda. La neurona, el gradiente, la retropropagación, la\n",
    "convolución y la atención. Todo en veinte líneas cada una y con sus números\n",
    "impresos 🔧\n",
    "\n",
    "No porque en el trabajo se haga así, sino porque es la única forma de que\n",
    "después, cuando uses una librería, sepas qué está pasando."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. La red más pequeña posible\n",
    "\n",
    "Una sola neurona escondida. Mira contra qué se parece."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 1\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Cuántos pesos tiene cada arquitectura\n",
    "\n",
    "Cuenta los parámetros sin entrenar nada, que salen de la\n",
    "forma de la red y de nada más."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 2\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Qué pasa si no escalas\n",
    "\n",
    "Quita el `StandardScaler` y entrena igual."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. La red sobre datos que sí tienen forma\n",
    "\n",
    "Fabrica un problema con estructura y repite la\n",
    "comparación."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 4\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. Lo mismo, pero dándole la pista a la logística\n",
    "\n",
    "Añade a mano las columnas al cuadrado y vuelve a medir."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 5\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. El error de darle texto crudo\n",
    "\n",
    "Pásale la ciudad tal cual, sin codificar, a ver qué dice."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 6\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. La pregunta para la próxima propuesta que te llegue\n",
    "\n",
    "Arma la tabla que yo pediría antes de aprobar una red."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 7\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "En las 3.000 ventas la red saca 0,5834 y la regresión logística 0,7214. ¿Qué haces?\n",
    "\n",
    "a) Uso la logística, y guardo la red para cuando haya imágenes o texto\n",
    "\n",
    "b) Entreno la red más vueltas\n",
    "\n",
    "c) Le añado más capas\n",
    "\n",
    "d) Reviso los datos, porque una red no puede perder"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## La comparación que sale al revés"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### La trampa\n",
    "\n",
    "Comparas la red contra la regresión logística para decidir cuál se queda. Miras la nota de las dos y la red gana por goleada.\n",
    "\n",
    "```\n",
    "log.fit(X_tr, y_tr)\n",
    "red.fit(X_tr, y_tr)\n",
    "\n",
    "print('logistica:', log.score(X_tr, y_tr))\n",
    "print('red      :', red.score(X_tr, y_tr))\n",
    "\n",
    "# logistica: 0.73\n",
    "# red      : 1.00\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": [
    "- 📉 Sobre estos datos en tabla la red pierde: 0,7214 la logística contra\n",
    "0,6584 y 0,5834.\n",
    "\n",
    "- 🧠 Y memoriza: la red de 64 y 32 llega a 1,0000 de AUC en entrenamiento.\n",
    "\n",
    "- 🛑 Con parada temprana y penalización mejora mucho (0,7018 y 0,7072) y\n",
    "sigue perdiendo.\n",
    "\n",
    "- 🖼️ La red gana cuando el dato tiene forma: píxeles vecinos, palabras en\n",
    "orden, tiempo.\n",
    "\n",
    "- ⭕ En un problema circular fabricado, la logística da 0,4867 y la red\n",
    "0,9999. Y la logística llega a 1,0 si le das los cuadrados a mano.\n",
    "\n",
    "- 🧱 Una red de una neurona es casi una regresión logística. No hay salto\n",
    "conceptual, hay apilamiento.\n",
    "\n",
    "- ⚖️ Sin escalar, esta red sacó 0,6925 y escalada 0,6584. La explicación\n",
    "que le iba a poner no aguantó la comprobación, así que va el número y no el\n",
    "cuento.\n",
    "\n",
    "- 📋 Antes de aprobar una red, la tabla de tres filas: tonto, simple y red.\n",
    "\n",
    "Y si de todo el capítulo te llevas una sola frase, que sea esta:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Una red que memoriza no es una red potente. Es una red sin nada que aprender."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La regresión logística contra la que pierde la red está explicada entera en el [libro de machine learning desde cero](https://missyera.com/guias/machine-learning-desde-cero/) 📊\n",
    "\n",
    "En el capítulo 2 escribimos la neurona a mano, con numpy y sin librería, para\n",
    "ver que por dentro son cuatro cuentas.\n",
    "\n",
    "Que tengas lindo día! 🌸"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 1 de **Deep learning desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/deep-learning-desde-cero/cuando-si-y-cuando-no/\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
}
