{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Construir un modelo de regresión logística - Lección 4\n", "\n", "![Infografía de regresión logística vs. regresión lineal](../../../../../../translated_images/linear-vs-logistic.ba180bf95e7ee66721ba10ebf2dac2666acbd64a88b003c83928712433a13c7d.es.png)\n", "\n", "#### **[Cuestionario previo a la lección](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n", "\n", "#### Introducción\n", "\n", "En esta última lección sobre Regresión, una de las técnicas básicas *clásicas* de Machine Learning, echaremos un vistazo a la Regresión Logística. Utilizarías esta técnica para descubrir patrones y predecir categorías binarias. ¿Es este dulce de chocolate o no? ¿Es esta enfermedad contagiosa o no? ¿Elegirá este cliente este producto o no?\n", "\n", "En esta lección, aprenderás:\n", "\n", "- Técnicas para la regresión logística\n", "\n", "✅ Profundiza tu comprensión sobre cómo trabajar con este tipo de regresión en este [módulo de aprendizaje](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)\n", "\n", "## Prerrequisito\n", "\n", "Habiendo trabajado con los datos de calabazas, ahora estamos lo suficientemente familiarizados con ellos como para darnos cuenta de que hay una categoría binaria con la que podemos trabajar: `Color`.\n", "\n", "Construyamos un modelo de regresión logística para predecir, dado algunas variables, *de qué color es probable que sea una calabaza* (naranja 🎃 o blanca 👻).\n", "\n", "> ¿Por qué estamos hablando de clasificación binaria en una lección sobre regresión? Solo por conveniencia lingüística, ya que la regresión logística es [en realidad un método de clasificación](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), aunque basado en un modelo lineal. Aprende sobre otras formas de clasificar datos en el próximo grupo de lecciones.\n", "\n", "Para esta lección, necesitaremos los siguientes paquetes:\n", "\n", "- `tidyverse`: El [tidyverse](https://www.tidyverse.org/) es una [colección de paquetes de R](https://www.tidyverse.org/packages) diseñada para hacer la ciencia de datos más rápida, fácil y divertida.\n", "\n", "- `tidymodels`: El marco de trabajo [tidymodels](https://www.tidymodels.org/) es una [colección de paquetes](https://www.tidymodels.org/packages/) para modelado y aprendizaje automático.\n", "\n", "- `janitor`: El paquete [janitor](https://github.com/sfirke/janitor) proporciona herramientas simples para examinar y limpiar datos desordenados.\n", "\n", "- `ggbeeswarm`: El paquete [ggbeeswarm](https://github.com/eclarke/ggbeeswarm) ofrece métodos para crear gráficos estilo \"beeswarm\" utilizando ggplot2.\n", "\n", "Puedes instalarlos con:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n", "\n", "Alternativamente, el siguiente script verifica si tienes los paquetes necesarios para completar este módulo y los instala por ti en caso de que falten.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n", "\n", "pacman::p_load(tidyverse, tidymodels, janitor, ggbeeswarm)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **Definir la pregunta**\n", "\n", "Para nuestros propósitos, expresaremos esto como un binario: 'Blanco' o 'No Blanco'. También hay una categoría 'rayado' en nuestro conjunto de datos, pero hay pocos casos de ella, así que no la usaremos. De todos modos, desaparece una vez que eliminamos los valores nulos del conjunto de datos.\n", "\n", "> 🎃 Dato curioso: a veces llamamos a las calabazas blancas 'calabazas fantasma'. No son muy fáciles de tallar, por lo que no son tan populares como las naranjas, ¡pero tienen un aspecto genial! Así que también podríamos reformular nuestra pregunta como: 'Fantasma' o 'No Fantasma'. 👻\n", "\n", "## **Sobre la regresión logística**\n", "\n", "La regresión logística difiere de la regresión lineal, que aprendiste anteriormente, en algunos aspectos importantes.\n", "\n", "#### **Clasificación binaria**\n", "\n", "La regresión logística no ofrece las mismas características que la regresión lineal. La primera ofrece una predicción sobre una `categoría binaria` (\"naranja o no naranja\"), mientras que la segunda es capaz de predecir `valores continuos`, por ejemplo, dado el origen de una calabaza y el momento de la cosecha, *cuánto aumentará su precio*.\n", "\n", "![Infografía por Dasani Madipalli](../../../../../../translated_images/pumpkin-classifier.562771f104ad5436b87d1c67bca02a42a17841133556559325c0a0e348e5b774.es.png)\n", "\n", "### Otras clasificaciones\n", "\n", "Existen otros tipos de regresión logística, incluyendo multinomial y ordinal:\n", "\n", "- **Multinomial**, que implica tener más de una categoría - \"Naranja, Blanco y Rayado\".\n", "\n", "- **Ordinal**, que implica categorías ordenadas, útil si quisiéramos ordenar nuestros resultados lógicamente, como nuestras calabazas que están ordenadas por un número finito de tamaños (mini,pequeño,mediano,grande,xl,xxl).\n", "\n", "![Regresión multinomial vs ordinal](../../../../../../translated_images/multinomial-vs-ordinal.36701b4850e37d86c9dd49f7bef93a2f94dbdb8fe03443eb68f0542f97f28f29.es.png)\n", "\n", "#### **Las variables NO tienen que correlacionarse**\n", "\n", "¿Recuerdas cómo la regresión lineal funcionaba mejor con variables más correlacionadas? La regresión logística es lo opuesto: las variables no tienen que alinearse. Esto funciona para estos datos que tienen correlaciones algo débiles.\n", "\n", "#### **Necesitas muchos datos limpios**\n", "\n", "La regresión logística dará resultados más precisos si utilizas más datos; nuestro conjunto de datos pequeño no es óptimo para esta tarea, así que tenlo en cuenta.\n", "\n", "✅ Piensa en los tipos de datos que se prestarían bien para la regresión logística.\n", "\n", "## Ejercicio - ordenar los datos\n", "\n", "Primero, limpia un poco los datos, eliminando valores nulos y seleccionando solo algunas de las columnas:\n", "\n", "1. Agrega el siguiente código:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Load the core tidyverse packages\n", "library(tidyverse)\n", "\n", "# Import the data and clean column names\n", "pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\") %>% \n", " clean_names()\n", "\n", "# Select desired columns\n", "pumpkins_select <- pumpkins %>% \n", " select(c(city_name, package, variety, origin, item_size, color)) \n", "\n", "# Drop rows containing missing values and encode color as factor (category)\n", "pumpkins_select <- pumpkins_select %>% \n", " drop_na() %>% \n", " mutate(color = factor(color))\n", "\n", "# View the first few rows\n", "pumpkins_select %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Siempre puedes echar un vistazo a tu nuevo dataframe utilizando la función [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html) como se muestra a continuación:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "pumpkins_select %>% \n", " glimpse()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Confirmemos que, de hecho, vamos a trabajar en un problema de clasificación binaria:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Subset distinct observations in outcome column\n", "pumpkins_select %>% \n", " distinct(color)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Visualización - gráfico categórico\n", "A estas alturas, ya has cargado nuevamente los datos de las calabazas y los has limpiado para conservar un conjunto de datos que incluye algunas variables, como el Color. Vamos a visualizar el dataframe en el notebook utilizando la biblioteca ggplot.\n", "\n", "La biblioteca ggplot ofrece formas interesantes de visualizar tus datos. Por ejemplo, puedes comparar las distribuciones de los datos para cada Variedad y Color en un gráfico categórico.\n", "\n", "1. Crea un gráfico de este tipo utilizando la función geombar, con los datos de las calabazas, y especificando un mapeo de color para cada categoría de calabaza (naranja o blanca):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# Specify colors for each value of the hue variable\n", "palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n", "\n", "# Create the bar plot\n", "ggplot(pumpkins_select, aes(y = variety, fill = color)) +\n", " geom_bar(position = \"dodge\") +\n", " scale_fill_manual(values = palette) +\n", " labs(y = \"Variety\", fill = \"Color\") +\n", " theme_minimal()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Al observar los datos, puedes ver cómo los datos de Color se relacionan con la Variedad.\n", "\n", "✅ Dado este gráfico categórico, ¿qué exploraciones interesantes puedes imaginar?\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Preprocesamiento de datos: codificación de características\n", "\n", "Nuestro conjunto de datos de calabazas contiene valores de tipo cadena en todas sus columnas. Trabajar con datos categóricos es intuitivo para los humanos, pero no para las máquinas. Los algoritmos de aprendizaje automático funcionan mejor con números. Por eso, la codificación es un paso muy importante en la fase de preprocesamiento de datos, ya que nos permite convertir datos categóricos en datos numéricos sin perder información. Una buena codificación conduce a la construcción de un buen modelo.\n", "\n", "Para la codificación de características, existen dos tipos principales de codificadores:\n", "\n", "1. Codificador ordinal: es adecuado para variables ordinales, que son variables categóricas donde sus datos siguen un orden lógico, como la columna `item_size` en nuestro conjunto de datos. Crea un mapeo de manera que cada categoría se representa con un número, que corresponde al orden de la categoría en la columna.\n", "\n", "2. Codificador categórico: es adecuado para variables nominales, que son variables categóricas donde sus datos no siguen un orden lógico, como todas las características diferentes de `item_size` en nuestro conjunto de datos. Es una codificación de tipo one-hot, lo que significa que cada categoría se representa con una columna binaria: la variable codificada es igual a 1 si la calabaza pertenece a esa variedad y 0 en caso contrario.\n", "\n", "Tidymodels ofrece otro paquete interesante: [recipes](https://recipes.tidymodels.org/), un paquete para el preprocesamiento de datos. Definiremos una `recipe` que especifica que todas las columnas predictoras deben codificarse en un conjunto de enteros, la `prep` para estimar las cantidades y estadísticas necesarias para cualquier operación, y finalmente la `bake` para aplicar los cálculos a nuevos datos.\n", "\n", "> Normalmente, recipes se utiliza como un preprocesador para modelado, donde define qué pasos deben aplicarse a un conjunto de datos para que esté listo para el modelado. En ese caso, es **altamente recomendable** que utilices un `workflow()` en lugar de estimar manualmente una receta usando prep y bake. Veremos todo esto en un momento.\n", ">\n", "> Sin embargo, por ahora, estamos utilizando recipes + prep + bake para especificar qué pasos deben aplicarse a un conjunto de datos para que esté listo para el análisis de datos y luego extraer los datos preprocesados con los pasos aplicados.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Preprocess and extract data to allow some data analysis\n", "baked_pumpkins <- recipe(color ~ ., data = pumpkins_select) %>%\n", " # Define ordering for item_size column\n", " step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n", " # Convert factors to numbers using the order defined above (Ordinal encoding)\n", " step_integer(item_size, zero_based = F) %>%\n", " # Encode all other predictors using one hot encoding\n", " step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE) %>%\n", " prep(data = pumpkin_select) %>%\n", " bake(new_data = NULL)\n", "\n", "# Display the first few rows of preprocessed data\n", "baked_pumpkins %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "✅ ¿Cuáles son las ventajas de usar un codificador ordinal para la columna Item Size?\n", "\n", "### Analizar las relaciones entre variables\n", "\n", "Ahora que hemos preprocesado nuestros datos, podemos analizar las relaciones entre las características y la etiqueta para hacernos una idea de qué tan bien el modelo podrá predecir la etiqueta a partir de las características. La mejor manera de realizar este tipo de análisis es graficando los datos. \n", "Usaremos nuevamente la función ggplot geom_boxplot_ para visualizar las relaciones entre Item Size, Variety y Color en un gráfico categórico. Para representar mejor los datos, utilizaremos la columna codificada de Item Size y la columna no codificada de Variety.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Define the color palette\n", "palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n", "\n", "# We need the encoded Item Size column to use it as the x-axis values in the plot\n", "pumpkins_select_plot<-pumpkins_select\n", "pumpkins_select_plot$item_size <- baked_pumpkins$item_size\n", "\n", "# Create the grouped box plot\n", "ggplot(pumpkins_select_plot, aes(x = `item_size`, y = color, fill = color)) +\n", " geom_boxplot() +\n", " facet_grid(variety ~ ., scales = \"free_x\") +\n", " scale_fill_manual(values = palette) +\n", " labs(x = \"Item Size\", y = \"\") +\n", " theme_minimal() +\n", " theme(strip.text = element_text(size = 12)) +\n", " theme(axis.text.x = element_text(size = 10)) +\n", " theme(axis.title.x = element_text(size = 12)) +\n", " theme(axis.title.y = element_blank()) +\n", " theme(legend.position = \"bottom\") +\n", " guides(fill = guide_legend(title = \"Color\")) +\n", " theme(panel.spacing = unit(0.5, \"lines\"))+\n", " theme(strip.text.y = element_text(size = 4, hjust = 0)) \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Usar un gráfico de enjambre\n", "\n", "Dado que Color es una categoría binaria (Blanco o No), requiere 'un [enfoque especializado](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf) para su visualización'.\n", "\n", "Prueba un `gráfico de enjambre` para mostrar la distribución del color con respecto al tamaño del artículo.\n", "\n", "Usaremos el [paquete ggbeeswarm](https://github.com/eclarke/ggbeeswarm), que proporciona métodos para crear gráficos estilo enjambre utilizando ggplot2. Los gráficos de enjambre son una forma de representar puntos que normalmente se superpondrían, de manera que se posicionen uno al lado del otro.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Create beeswarm plots of color and item_size\n", "baked_pumpkins %>% \n", " mutate(color = factor(color)) %>% \n", " ggplot(mapping = aes(x = color, y = item_size, color = color)) +\n", " geom_quasirandom() +\n", " scale_color_brewer(palette = \"Dark2\", direction = -1) +\n", " theme(legend.position = \"none\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ahora que tenemos una idea de la relación entre las categorías binarias de color y el grupo más amplio de tamaños, exploremos la regresión logística para determinar el color probable de una calabaza.\n", "\n", "## Construye tu modelo\n", "\n", "Selecciona las variables que deseas usar en tu modelo de clasificación y divide los datos en conjuntos de entrenamiento y prueba. [rsample](https://rsample.tidymodels.org/), un paquete de Tidymodels, proporciona infraestructura para una división y remuestreo de datos eficiente:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Split data into 80% for training and 20% for testing\n", "set.seed(2056)\n", "pumpkins_split <- pumpkins_select %>% \n", " initial_split(prop = 0.8)\n", "\n", "# Extract the data in each split\n", "pumpkins_train <- training(pumpkins_split)\n", "pumpkins_test <- testing(pumpkins_split)\n", "\n", "# Print out the first 5 rows of the training set\n", "pumpkins_train %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "🙌 Ahora estamos listos para entrenar un modelo ajustando las características de entrenamiento a la etiqueta de entrenamiento (color).\n", "\n", "Comenzaremos creando una receta que especifique los pasos de preprocesamiento que deben realizarse en nuestros datos para prepararlos para el modelado, es decir: codificar variables categóricas en un conjunto de enteros. Al igual que `baked_pumpkins`, creamos una `pumpkins_recipe` pero no usamos `prep` ni `bake`, ya que esto se integrará en un flujo de trabajo, como verás en unos pocos pasos.\n", "\n", "Existen varias formas de especificar un modelo de regresión logística en Tidymodels. Consulta `?logistic_reg()`. Por ahora, especificaremos un modelo de regresión logística mediante el motor predeterminado `stats::glm()`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Create a recipe that specifies preprocessing steps for modelling\n", "pumpkins_recipe <- recipe(color ~ ., data = pumpkins_train) %>% \n", " step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n", " step_integer(item_size, zero_based = F) %>% \n", " step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE)\n", "\n", "# Create a logistic model specification\n", "log_reg <- logistic_reg() %>% \n", " set_engine(\"glm\") %>% \n", " set_mode(\"classification\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ahora que tenemos una receta y una especificación del modelo, necesitamos encontrar una forma de combinarlas en un objeto que primero preprocese los datos (prep+bake detrás de escena), ajuste el modelo con los datos preprocesados y también permita posibles actividades de postprocesamiento.\n", "\n", "En Tidymodels, este práctico objeto se llama [`workflow`](https://workflows.tidymodels.org/) y organiza convenientemente los componentes de tu modelo.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Bundle modelling components in a workflow\n", "log_reg_wf <- workflow() %>% \n", " add_recipe(pumpkins_recipe) %>% \n", " add_model(log_reg)\n", "\n", "# Print out the workflow\n", "log_reg_wf\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Después de que se haya *especificado* un flujo de trabajo, se puede `entrenar` un modelo utilizando la función [`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html). El flujo de trabajo estimará una receta y preprocesará los datos antes del entrenamiento, por lo que no será necesario hacerlo manualmente utilizando prep y bake.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Train the model\n", "wf_fit <- log_reg_wf %>% \n", " fit(data = pumpkins_train)\n", "\n", "# Print the trained workflow\n", "wf_fit\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El modelo muestra los coeficientes aprendidos durante el entrenamiento.\n", "\n", "Ahora que hemos entrenado el modelo utilizando los datos de entrenamiento, podemos hacer predicciones sobre los datos de prueba usando [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). Comencemos utilizando el modelo para predecir etiquetas para nuestro conjunto de prueba y las probabilidades de cada etiqueta. Cuando la probabilidad es mayor a 0.5, la clase predicha es `WHITE`, de lo contrario, es `ORANGE`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Make predictions for color and corresponding probabilities\n", "results <- pumpkins_test %>% select(color) %>% \n", " bind_cols(wf_fit %>% \n", " predict(new_data = pumpkins_test)) %>%\n", " bind_cols(wf_fit %>%\n", " predict(new_data = pumpkins_test, type = \"prob\"))\n", "\n", "# Compare predictions\n", "results %>% \n", " slice_head(n = 10)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "¡Muy bien! Esto proporciona más información sobre cómo funciona la regresión logística.\n", "\n", "### Mejor comprensión mediante una matriz de confusión\n", "\n", "Comparar cada predicción con su valor \"real\" correspondiente no es una forma muy eficiente de determinar qué tan bien está prediciendo el modelo. Afortunadamente, Tidymodels tiene algunos trucos más bajo la manga: [`yardstick`](https://yardstick.tidymodels.org/) - un paquete utilizado para medir la efectividad de los modelos mediante métricas de rendimiento.\n", "\n", "Una métrica de rendimiento asociada con problemas de clasificación es la [`matriz de confusión`](https://wikipedia.org/wiki/Confusion_matrix). Una matriz de confusión describe qué tan bien funciona un modelo de clasificación. Una matriz de confusión tabula cuántos ejemplos de cada clase fueron clasificados correctamente por un modelo. En nuestro caso, te mostrará cuántas calabazas naranjas fueron clasificadas como naranjas y cuántas calabazas blancas fueron clasificadas como blancas; la matriz de confusión también te mostrará cuántas fueron clasificadas en las categorías **incorrectas**.\n", "\n", "La función [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) de yardstick calcula esta tabulación cruzada de clases observadas y predichas.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Confusion matrix for prediction results\n", "conf_mat(data = results, truth = color, estimate = .pred_class)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vamos a interpretar la matriz de confusión. Nuestro modelo debe clasificar calabazas entre dos categorías binarias, la categoría `blanca` y la categoría `no blanca`.\n", "\n", "- Si tu modelo predice que una calabaza es blanca y en realidad pertenece a la categoría 'blanca', lo llamamos un `verdadero positivo`, representado por el número en la esquina superior izquierda.\n", "\n", "- Si tu modelo predice que una calabaza no es blanca y en realidad pertenece a la categoría 'blanca', lo llamamos un `falso negativo`, representado por el número en la esquina inferior izquierda.\n", "\n", "- Si tu modelo predice que una calabaza es blanca y en realidad pertenece a la categoría 'no blanca', lo llamamos un `falso positivo`, representado por el número en la esquina superior derecha.\n", "\n", "- Si tu modelo predice que una calabaza no es blanca y en realidad pertenece a la categoría 'no blanca', lo llamamos un `verdadero negativo`, representado por el número en la esquina inferior derecha.\n", "\n", "| Verdad |\n", "|:-----:|\n", "\n", "\n", "| | | |\n", "|---------------|--------|-------|\n", "| **Predicción** | BLANCA | NARANJA |\n", "| BLANCA | VP | FP |\n", "| NARANJA | FN | VN |\n", "\n", "Como habrás adivinado, es preferible tener un mayor número de verdaderos positivos y verdaderos negativos, y un menor número de falsos positivos y falsos negativos, lo que implica que el modelo tiene un mejor desempeño.\n", "\n", "La matriz de confusión es útil porque da lugar a otras métricas que nos ayudan a evaluar mejor el rendimiento de un modelo de clasificación. Vamos a repasarlas:\n", "\n", "🎓 Precisión: `VP/(VP + FP)` definida como la proporción de positivos predichos que realmente son positivos. También conocida como [valor predictivo positivo](https://es.wikipedia.org/wiki/Valor_predictivo_positivo \"Valor predictivo positivo\").\n", "\n", "🎓 Recall: `VP/(VP + FN)` definida como la proporción de resultados positivos sobre el número de muestras que realmente eran positivas. También conocida como `sensibilidad`.\n", "\n", "🎓 Especificidad: `VN/(VN + FP)` definida como la proporción de resultados negativos sobre el número de muestras que realmente eran negativas.\n", "\n", "🎓 Exactitud: `VP + VN/(VP + VN + FP + FN)` El porcentaje de etiquetas predichas correctamente para una muestra.\n", "\n", "🎓 Medida F: Un promedio ponderado entre la precisión y el recall, donde el mejor valor es 1 y el peor es 0.\n", "\n", "¡Vamos a calcular estas métricas!\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Combine metric functions and calculate them all at once\n", "eval_metrics <- metric_set(ppv, recall, spec, f_meas, accuracy)\n", "eval_metrics(data = results, truth = color, estimate = .pred_class)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Visualizar la curva ROC de este modelo\n", "\n", "Hagamos una visualización más para observar la llamada [`curva ROC`](https://en.wikipedia.org/wiki/Receiver_operating_characteristic):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Make a roc_curve\n", "results %>% \n", " roc_curve(color, .pred_ORANGE) %>% \n", " autoplot()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Las curvas ROC se utilizan frecuentemente para obtener una visión del rendimiento de un clasificador en términos de sus verdaderos positivos frente a los falsos positivos. Las curvas ROC suelen mostrar la `Tasa de Verdaderos Positivos`/Sensibilidad en el eje Y, y la `Tasa de Falsos Positivos`/1-Especificidad en el eje X. Por lo tanto, la inclinación de la curva y el espacio entre la línea del punto medio y la curva son importantes: se busca una curva que suba rápidamente y se aleje de la línea. En nuestro caso, hay falsos positivos al principio, y luego la línea sube y se aleja correctamente.\n", "\n", "Finalmente, usemos `yardstick::roc_auc()` para calcular el Área Bajo la Curva. Una forma de interpretar el AUC es como la probabilidad de que el modelo clasifique un ejemplo positivo aleatorio más alto que un ejemplo negativo aleatorio.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Calculate area under curve\n", "results %>% \n", " roc_auc(color, .pred_ORANGE)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El resultado es alrededor de `0.975`. Dado que el AUC varía de 0 a 1, quieres un puntaje alto, ya que un modelo que sea 100% correcto en sus predicciones tendrá un AUC de 1; en este caso, el modelo es *bastante bueno*.\n", "\n", "En futuras lecciones sobre clasificaciones, aprenderás cómo mejorar los puntajes de tu modelo (como manejar datos desbalanceados en este caso).\n", "\n", "## 🚀Desafío\n", "\n", "¡Hay mucho más que explorar sobre la regresión logística! Pero la mejor manera de aprender es experimentar. Encuentra un conjunto de datos que se preste a este tipo de análisis y construye un modelo con él. ¿Qué aprendes? consejo: prueba [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) para conjuntos de datos interesantes.\n", "\n", "## Revisión y Autoestudio\n", "\n", "Lee las primeras páginas de [este artículo de Stanford](https://web.stanford.edu/~jurafsky/slp3/5.pdf) sobre algunos usos prácticos de la regresión logística. Piensa en tareas que sean más adecuadas para uno u otro tipo de tareas de regresión que hemos estudiado hasta ahora. ¿Qué funcionaría mejor?\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**Descargo de responsabilidad**: \nEste documento ha sido traducido utilizando el servicio de traducción automática [Co-op Translator](https://github.com/Azure/co-op-translator). Si bien nos esforzamos por lograr precisión, tenga en cuenta que las traducciones automáticas pueden contener errores o imprecisiones. El documento original en su idioma nativo debe considerarse como la fuente autorizada. Para información crítica, se recomienda una traducción profesional realizada por humanos. No nos hacemos responsables de malentendidos o interpretaciones erróneas que puedan surgir del uso de esta traducción.\n" ] } ], "metadata": { "anaconda-cloud": "", "kernelspec": { "display_name": "R", "langauge": "R", "name": "ir" }, "language_info": { "codemirror_mode": "r", "file_extension": ".r", "mimetype": "text/x-r-source", "name": "R", "pygments_lexer": "r", "version": "3.4.1" }, "coopTranslator": { "original_hash": "feaf125f481a89c468fa115bf2aed580", "translation_date": "2025-09-04T01:24:55+00:00", "source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb", "language_code": "es" } }, "nbformat": 4, "nbformat_minor": 1 }