{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sumar y escalar, que ya es media predicción\n",
    "\n",
    "Las dos únicas operaciones que necesitas para entender qué hace un modelo lineal por dentro, con la tabla de ventas de siempre.\n",
    "\n",
    "Cuaderno de soluciones del capítulo 3 de **Matemática para machine learning**, 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/matematica-para-machine-learning/suma-y-escalado-de-vectores/\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": [
    "## Antes de empezar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import urllib.request\n",
    "\n",
    "# Este capitulo abre el archivo por su nombre, sin URL, que es lo que se hace\n",
    "# cuando lo tienes al lado. Aqui se baja primero para que exista.\n",
    "for nombre in ['ventas-miss-yera.csv']:\n",
    "    urllib.request.urlretrieve(f\"https://missyera.com/static/datasets/{nombre}\", nombre)\n",
    "    print(nombre, \"lista\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dos operaciones y ya está 🌸"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Este capítulo es corto porque los vectores solo saben hacer dos cosas:\n",
    "sumarse entre ellos y estirarse. Con eso se construye todo lo demás."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Volvemos a abrir el archivo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cada capítulo arranca de cero, así que estas líneas se repiten. Son las\n",
    "mismas del capítulo 1 y las vas a ver en todos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "df = pd.read_csv('ventas-miss-yera.csv')\n",
    "for c in ('unidades', 'monto', 'satisfaccion'):\n",
    "    df[c] = pd.to_numeric(df[c], errors='coerce')\n",
    "X = df[['unidades', 'monto', 'satisfaccion']].dropna().to_numpy()\n",
    "print('X.shape:', X.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Sumar es componente con componente"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a, b = X[0], X[1]\n",
    "print('a     :', np.round(a, 2))\n",
    "print('b     :', np.round(b, 2))\n",
    "print('a + b :', np.round(a + b, 2))\n",
    "print('a - b :', np.round(a - b, 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Las unidades con las unidades, los soles con los soles. Nunca se cruzan."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "𝐚+𝐛=(a1+b1,a2+b2,…,ad+bd)\n",
    "\n",
    "sumar dos vectores es sumar componente con componente, cada una con la que le toca y con ninguna otra"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y mira la resta, que es la que de verdad se usa: `[0, -44.53, 1]`\n",
    "te dice que las dos ventas tuvieron las mismas unidades, que la segunda facturó\n",
    "44.53 soles más, y que la primera tuvo un punto más de satisfacción.\n",
    "\n",
    "Guárdate eso, porque **restar dos vectores es cómo se mide una\n",
    "diferencia**, y medir diferencias es lo que hace un modelo cuando calcula\n",
    "cuánto se equivocó. Eso es el capítulo de norma y distancia."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Escalar es estirar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('a * 2 :', np.round(a * 2, 2))\n",
    "print('a / 2 :', np.round(a / 2, 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "α𝐯=(αv1,αv2,…,αvd)\n",
    "\n",
    "multiplicar por un número escala todas las componentes por igual, sin cambiar la proporción entre ellas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ese número que multiplica se llama **escalar**, y el nombre no\n",
    "es casual: escala el vector sin cambiar la proporción entre sus componentes.\n",
    "\n",
    "Fíjate en `a * 2`: la satisfacción pasó a 8. Matemáticamente\n",
    "correcto y comercialmente absurdo, porque la escala llega a 5. Las operaciones\n",
    "no saben qué significan tus columnas: eso lo pones tú."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Y aquí está la predicción"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahora júntalas. Supón que quieres estimar cuánto vale una venta, y decides\n",
    "que cada unidad vale 12, cada sol facturado vale 0.35 y cada punto de\n",
    "satisfacción vale 40."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pesos = np.array([12.0, 0.35, 40.0])\n",
    "print('a       :', np.round(a, 2))\n",
    "print('pesos   :', pesos)\n",
    "print('a*pesos :', np.round(a * pesos, 2))\n",
    "print('suma    :', round(float((a * pesos).sum()), 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Multiplicar cada característica por su peso y sumarlo todo. **Eso es\n",
    "una predicción lineal.** Ese 448.13 es exactamente la forma que tiene la\n",
    "salida de una regresión lineal, de una regresión logística antes de la sigmoide,\n",
    "y de una sola neurona.\n",
    "\n",
    "La única diferencia entre esto y un modelo de verdad es de dónde salen los\n",
    "pesos. Yo me los inventé; un modelo los aprende. Cómo los aprende es la parte de\n",
    "optimización de este libro, y lo que hace en cada paso es el capítulo del\n",
    "descenso de gradiente.\n",
    "\n",
    "Y esa operación de \"multiplicar componente a componente y sumar\" es tan\n",
    "importante que tiene nombre propio y capítulo propio: el producto punto 🐣"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que te llevas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Sumar vectores es componente con componente. Nunca se cruzan.\n",
    "\n",
    "- Restar es cómo se mide una diferencia, y de ahí sale el error de un modelo.\n",
    "\n",
    "- Escalar es multiplicar todo por un número, sin cambiar las proporciones.\n",
    "\n",
    "- Pesar y sumar es literalmente lo que hace un modelo lineal.\n",
    "\n",
    "- Las operaciones no saben qué significan tus columnas."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comprueba que se entendió"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "Multiplicas cada característica de una venta por su peso y sumas todo. ¿Qué acabas de calcular?\n",
    "\n",
    "a) Una predicción lineal, que es lo que hace por dentro una regresión\n",
    "\n",
    "b) El promedio ponderado de la venta\n",
    "\n",
    "c) La distancia de esa venta al origen\n",
    "\n",
    "d) Nada útil, porque los pesos me los inventé yo\n",
    "\n",
    "---\n",
    "\n",
    "**La correcta es la a.**\n",
    "\n",
    "*b)* Le falta dividir entre la suma de los pesos. Sin esa división es otra cosa, y esa otra cosa es la que usan los modelos.\n",
    "\n",
    "*c)* Esa es la norma, que eleva al cuadrado y saca raíz. Aquí no hay ni cuadrados ni raíz.\n",
    "\n",
    "*d)* Los pesos inventados hacen que el número no sirva, pero la OPERACIÓN es exactamente la misma. Lo único que cambia en un modelo es de dónde salen los pesos.\n",
    "\n",
    "Pesar y sumar. Eso es una regresión lineal, una logística antes de la sigmoide y una neurona sola. Todo lo demás es cómo se aprenden esos pesos 💛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. El promedio es sumar y escalar\n",
    "\n",
    "Calcula la venta media a mano, sin usar mean."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "suma = X.sum(axis=0)\n",
    "media = suma / X.shape[0]\n",
    "print('a mano :', np.round(media, 2))\n",
    "print('mean   :', np.round(X.mean(axis=0), 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "a mano : [ 11.68 803.39   3.02]\n",
    "mean   : [ 11.68 803.39   3.02]\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Sumar todos los vectores y escalar por 1 partido el número de filas. El\n",
    "promedio no es una operación aparte: son las dos de este capítulo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Cambia los pesos y mira qué manda\n",
    "\n",
    "Pon a cero el peso del monto y compara."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sin_monto = np.array([12.0, 0.0, 40.0])\n",
    "print('con monto :', round(float((a * pesos).sum()), 2))\n",
    "print('sin monto :', round(float((a * sin_monto).sum()), 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "con monto : 448.13\n",
    "sin monto : 280.0\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Un peso en cero es lo mismo que borrar la columna. Y así es como se lee la\n",
    "importancia en un modelo lineal: el peso te dice cuánto pesa esa característica\n",
    "en el resultado. Con la trampa de que si las columnas están en escalas\n",
    "distintas, los pesos no se pueden comparar entre sí. Eso es el capítulo de\n",
    "escalado del libro de machine learning."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. La resta como error\n",
    "\n",
    "Compara la primera venta contra la venta media."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dif = a - X.mean(axis=0)\n",
    "print('diferencia :', np.round(dif, 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "diferencia : [  -1.68 -323.02    0.98]\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esta venta tuvo 1.68 unidades menos que la media, facturó 323.02 soles menos\n",
    "y tuvo casi un punto más de satisfacción. Ese vector de diferencias es la\n",
    "materia prima de casi todo: de la varianza, de la distancia y del error de un\n",
    "modelo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Preguntas frecuentes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "¿Cómo se hace la suma de vectores?Se suman componente a componente y sale otro vector del mismo largo. Si los largos no coinciden, la operación no existe.\n",
    "\n",
    "¿Y la resta de vectores?Igual, componente a componente. La resta de dos vectores es la flecha que va de uno al otro, y por eso mide la distancia entre dos clientes.\n",
    "\n",
    "¿Qué es multiplicar un vector por un escalar?Multiplicar cada componente por el mismo número. Estira el vector si el número es mayor que uno, lo encoge si es menor, y lo da vuelta si es negativo.\n",
    "\n",
    "¿Qué son las operaciones con vectores?Sumar, restar, escalar y el producto punto. Con esas cuatro está hecho casi todo lo que un modelo lineal calcula."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 3 de **Matemática para machine learning**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/matematica-para-machine-learning/suma-y-escalado-de-vectores/\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
}
