{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_2-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "f3c335f9940cfd76528b3ef918b9b342", "translation_date": "2025-09-04T01:42:10+00:00", "source_file": "2-Regression/2-Data/solution/R/lesson_2-R.ipynb", "language_code": "es" } }, "cells": [ { "cell_type": "markdown", "source": [ "# Construir un modelo de regresión: preparar y visualizar datos\n", "\n", "## **Regresión Lineal para Calabazas - Lección 2**\n", "#### Introducción\n", "\n", "Ahora que tienes las herramientas necesarias para comenzar a construir modelos de aprendizaje automático con Tidymodels y el Tidyverse, estás listo para empezar a formular preguntas sobre tus datos. Al trabajar con datos y aplicar soluciones de aprendizaje automático, es muy importante saber cómo hacer las preguntas correctas para desbloquear adecuadamente el potencial de tu conjunto de datos.\n", "\n", "En esta lección, aprenderás:\n", "\n", "- Cómo preparar tus datos para la construcción de modelos.\n", "\n", "- Cómo usar `ggplot2` para la visualización de datos.\n", "\n", "La pregunta que necesitas responder determinará qué tipo de algoritmos de aprendizaje automático utilizarás. Y la calidad de la respuesta que obtengas dependerá en gran medida de la naturaleza de tus datos.\n", "\n", "Veamos esto trabajando en un ejercicio práctico.\n", "\n", "\n", "
\n",
" \n",
"
\n",
"\n",
"> Un repaso: El operador pipe (`%>%`) realiza operaciones en secuencia lógica pasando un objeto hacia adelante dentro de una función o expresión. Puedes pensar en el operador pipe como si dijera \"y luego\" en tu código.\n"
],
"metadata": {
"id": "REWcIv9yX29v"
}
},
{
"cell_type": "markdown",
"source": [
"## 2. Verificar datos faltantes\n",
"\n",
"Uno de los problemas más comunes que los científicos de datos deben enfrentar es la falta o ausencia de datos. R representa los valores faltantes o desconocidos con un valor especial llamado `NA` (No Disponible).\n",
"\n",
"Entonces, ¿cómo podríamos saber si el marco de datos contiene valores faltantes? \n",
"
\n",
"- Una forma sencilla sería usar la función base de R `anyNA`, que devuelve los valores lógicos `TRUE` o `FALSE`.\n"
],
"metadata": {
"id": "Zxfb3AM5YbUe"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" anyNA()"
],
"outputs": [],
"metadata": {
"id": "G--DQutAYltj"
}
},
{
"cell_type": "markdown",
"source": [
"¡Genial, parece que falta algo de información! Ese es un buen punto de partida.\n",
"\n",
"- Otra forma sería usar la función `is.na()` que indica qué elementos individuales de la columna están ausentes con un valor lógico `TRUE`.\n"
],
"metadata": {
"id": "mU-7-SB6YokF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "W-DxDOR4YxSW"
}
},
{
"cell_type": "markdown",
"source": [
"Bien, trabajo hecho, pero con un marco de datos tan grande como este, sería ineficiente y prácticamente imposible revisar todas las filas y columnas individualmente😴.\n",
"\n",
"- Una forma más intuitiva sería calcular la suma de los valores faltantes para cada columna:\n"
],
"metadata": {
"id": "xUWxipKYY0o7"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" colSums()"
],
"outputs": [],
"metadata": {
"id": "ZRBWV6P9ZArL"
}
},
{
"cell_type": "markdown",
"source": [
"Mucho mejor. Faltan algunos datos, pero tal vez no importe para la tarea en cuestión. Veamos qué más nos revela el análisis.\n",
"\n",
"> Además de los increíbles conjuntos de paquetes y funciones, R tiene una documentación muy buena. Por ejemplo, usa `help(colSums)` o `?colSums` para obtener más información sobre la función.\n"
],
"metadata": {
"id": "9gv-crB6ZD1Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 3. Dplyr: Una gramática para la manipulación de datos\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "i5o33MQBZWWw"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::select()\n",
"\n",
"`select()` es una función del paquete `dplyr` que te ayuda a elegir columnas para mantener o excluir.\n",
"\n",
"Para que tu marco de datos sea más fácil de manejar, elimina varias de sus columnas utilizando `select()`, manteniendo solo las columnas que necesitas.\n",
"\n",
"Por ejemplo, en este ejercicio, nuestro análisis incluirá las columnas `Package`, `Low Price`, `High Price` y `Date`. Vamos a seleccionar estas columnas.\n"
],
"metadata": {
"id": "x3VGMAGBZiUr"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Select desired columns\n",
"pumpkins <- pumpkins %>% \n",
" select(Package, `Low Price`, `High Price`, Date)\n",
"\n",
"\n",
"# Print data set\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "F_FgxQnVZnM0"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::mutate()\n",
"\n",
"`mutate()` es una función del paquete `dplyr` que te ayuda a crear o modificar columnas, mientras mantienes las columnas existentes.\n",
"\n",
"La estructura general de `mutate` es:\n",
"\n",
"`data %>% mutate(new_column_name = what_it_contains)`\n",
"\n",
"Vamos a probar `mutate` utilizando la columna `Date` realizando las siguientes operaciones:\n",
"\n",
"1. Convertir las fechas (actualmente de tipo carácter) a un formato de mes (estas son fechas de EE.UU., por lo que el formato es `MM/DD/YYYY`).\n",
"\n",
"2. Extraer el mes de las fechas a una nueva columna.\n",
"\n",
"En R, el paquete [lubridate](https://lubridate.tidyverse.org/) facilita el trabajo con datos de tipo fecha y hora. Entonces, vamos a usar `dplyr::mutate()`, `lubridate::mdy()`, `lubridate::month()` y ver cómo lograr los objetivos mencionados. Podemos eliminar la columna `Date` ya que no la necesitaremos nuevamente en operaciones posteriores.\n"
],
"metadata": {
"id": "2KKo0Ed9Z1VB"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Load lubridate\n",
"library(lubridate)\n",
"\n",
"pumpkins <- pumpkins %>% \n",
" # Convert the Date column to a date object\n",
" mutate(Date = mdy(Date)) %>% \n",
" # Extract month from Date\n",
" mutate(Month = month(Date)) %>% \n",
" # Drop Date column\n",
" select(-Date)\n",
"\n",
"# View the first few rows\n",
"pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "5joszIVSZ6xe"
}
},
{
"cell_type": "markdown",
"source": [
"¡Genial! 🤩\n",
"\n",
"A continuación, vamos a crear una nueva columna `Price`, que representará el precio promedio de una calabaza. Ahora, tomemos el promedio de las columnas `Low Price` y `High Price` para llenar la nueva columna Price. \n",
"
\n"
],
"metadata": {
"id": "nIgLjNMCZ-6Y"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new column Price\n",
"pumpkins <- pumpkins %>% \n",
" mutate(Price = (`Low Price` + `High Price`)/2)\n",
"\n",
"# View the first few rows of the data\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "Zo0BsqqtaJw2"
}
},
{
"cell_type": "markdown",
"source": [
"¡Siií! 💪\n",
"\n",
"\"¡Pero espera!\", dirás después de echar un vistazo rápido a todo el conjunto de datos con `View(pumpkins)`, \"¡Aquí hay algo raro!\" 🤔\n",
"\n",
"Si miras la columna `Package`, las calabazas se venden en muchas configuraciones diferentes. Algunas se venden en medidas de `1 1/9 bushel`, otras en medidas de `1/2 bushel`, algunas por calabaza, otras por libra, y algunas en cajas grandes con anchos variables.\n",
"\n",
"Verifiquemos esto:\n"
],
"metadata": {
"id": "p77WZr-9aQAR"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Verify the distinct observations in Package column\n",
"pumpkins %>% \n",
" distinct(Package)"
],
"outputs": [],
"metadata": {
"id": "XISGfh0IaUy6"
}
},
{
"cell_type": "markdown",
"source": [
"¡Increíble!👏\n",
"\n",
"Las calabazas parecen ser muy difíciles de pesar de manera consistente, así que vamos a filtrarlas seleccionando solo las calabazas que tengan la cadena *bushel* en la columna `Package` y colocarlas en un nuevo marco de datos `new_pumpkins`.\n"
],
"metadata": {
"id": "7sMjiVujaZxY"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::filter() y stringr::str_detect()\n",
"\n",
"[`dplyr::filter()`](https://dplyr.tidyverse.org/reference/filter.html): crea un subconjunto de los datos que solo contiene las **filas** que cumplen con tus condiciones, en este caso, calabazas con la cadena *bushel* en la columna `Package`.\n",
"\n",
"[stringr::str_detect()](https://stringr.tidyverse.org/reference/str_detect.html): detecta la presencia o ausencia de un patrón en una cadena de texto.\n",
"\n",
"El paquete [`stringr`](https://github.com/tidyverse/stringr) proporciona funciones simples para operaciones comunes con cadenas de texto.\n"
],
"metadata": {
"id": "L8Qfcs92ageF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Retain only pumpkins with \"bushel\"\n",
"new_pumpkins <- pumpkins %>% \n",
" filter(str_detect(Package, \"bushel\"))\n",
"\n",
"# Get the dimensions of the new data\n",
"dim(new_pumpkins)\n",
"\n",
"# View a few rows of the new data\n",
"new_pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "hy_SGYREampd"
}
},
{
"cell_type": "markdown",
"source": [
"Puedes ver que hemos reducido a unas 415 filas de datos que contienen calabazas por fanega. 🤩 \n",
"
\n"
],
"metadata": {
"id": "VrDwF031avlR"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::case_when()\n",
"\n",
"**Pero espera, ¡hay algo más por hacer!**\n",
"\n",
"¿Notaste que la cantidad de bushels varía por fila? Necesitas normalizar los precios para mostrar el precio por bushel, no por 1 1/9 o 1/2 bushel. Es hora de hacer algunos cálculos para estandarizarlo.\n",
"\n",
"Usaremos la función [`case_when()`](https://dplyr.tidyverse.org/reference/case_when.html) para *mutar* la columna de Precio dependiendo de algunas condiciones. `case_when` te permite vectorizar múltiples declaraciones `if_else()`.\n"
],
"metadata": {
"id": "mLpw2jH4a0tx"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Convert the price if the Package contains fractional bushel values\n",
"new_pumpkins <- new_pumpkins %>% \n",
" mutate(Price = case_when(\n",
" str_detect(Package, \"1 1/9\") ~ Price/(1 + 1/9),\n",
" str_detect(Package, \"1/2\") ~ Price/(1/2),\n",
" TRUE ~ Price))\n",
"\n",
"# View the first few rows of the data\n",
"new_pumpkins %>% \n",
" slice_head(n = 30)"
],
"outputs": [],
"metadata": {
"id": "P68kLVQmbM6I"
}
},
{
"cell_type": "markdown",
"source": [
"Ahora podemos analizar el precio por unidad basado en su medida en fanegas. Todo este estudio de fanegas de calabazas, sin embargo, demuestra lo `importante` que es `entender la naturaleza de tus datos`.\n",
"\n",
"> ✅ Según [The Spruce Eats](https://www.thespruceeats.com/how-much-is-a-bushel-1389308), el peso de una fanega depende del tipo de producto, ya que es una medida de volumen. \"Una fanega de tomates, por ejemplo, se supone que pesa 56 libras... Las hojas y verduras ocupan más espacio con menos peso, por lo que una fanega de espinacas pesa solo 20 libras.\" ¡Es todo bastante complicado! No nos molestemos en hacer una conversión de fanegas a libras, y en su lugar fijemos el precio por fanega. Todo este estudio de fanegas de calabazas, sin embargo, demuestra lo importante que es entender la naturaleza de tus datos.\n",
">\n",
"> ✅ ¿Notaste que las calabazas vendidas por media fanega son muy caras? ¿Puedes averiguar por qué? Pista: las calabazas pequeñas son mucho más caras que las grandes, probablemente porque hay muchas más de ellas por fanega, dado el espacio no utilizado que ocupa una gran calabaza hueca para pastel.\n"
],
"metadata": {
"id": "pS2GNPagbSdb"
}
},
{
"cell_type": "markdown",
"source": [
"Ahora, por último, solo por el simple gusto de la aventura 💁♀️, movamos también la columna de Mes a la primera posición, es decir, `antes` de la columna `Paquete`.\n",
"\n",
"Se utiliza `dplyr::relocate()` para cambiar las posiciones de las columnas.\n"
],
"metadata": {
"id": "qql1SowfbdnP"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new data frame new_pumpkins\n",
"new_pumpkins <- new_pumpkins %>% \n",
" relocate(Month, .before = Package)\n",
"\n",
"new_pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "JJ1x6kw8bixF"
}
},
{
"cell_type": "markdown",
"source": [
"¡Buen trabajo!👌 Ahora tienes un conjunto de datos limpio y ordenado sobre el cual puedes construir tu nuevo modelo de regresión. \n",
"
\n"
],
"metadata": {
"id": "y8TJ0Za_bn5Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 4. Visualización de datos con ggplot2\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "Ml7SDCLQcPvE"
}
},
{
"cell_type": "markdown",
"source": [
"### **¿Cómo lo hacemos útil?**\n",
"\n",
"Para que los gráficos muestren datos útiles, generalmente necesitas agrupar los datos de alguna manera. Por ejemplo, en nuestro caso, encontrar el precio promedio de las calabazas para cada mes proporcionaría más información sobre los patrones subyacentes en nuestros datos. Esto nos lleva a otro vistazo rápido de **dplyr**:\n",
"\n",
"#### `dplyr::group_by() %>% summarize()`\n",
"\n",
"La agregación agrupada en R se puede calcular fácilmente usando\n",
"\n",
"`dplyr::group_by() %>% summarize()`\n",
"\n",
"- `dplyr::group_by()` cambia la unidad de análisis del conjunto de datos completo a grupos individuales, como por mes.\n",
"\n",
"- `dplyr::summarize()` crea un nuevo marco de datos con una columna para cada variable de agrupación y una columna para cada estadística resumida que hayas especificado.\n",
"\n",
"Por ejemplo, podemos usar `dplyr::group_by() %>% summarize()` para agrupar las calabazas en grupos basados en la columna **Month** y luego encontrar el **precio promedio** para cada mes.\n"
],
"metadata": {
"id": "jMakvJZIcVkh"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Find the average price of pumpkins per month\r\n",
"new_pumpkins %>%\r\n",
" group_by(Month) %>% \r\n",
" summarise(mean_price = mean(Price))"
],
"outputs": [],
"metadata": {
"id": "6kVSUa2Bcilf"
}
},
{
"cell_type": "markdown",
"source": [
"¡Sucinto!✨\n",
"\n",
"Las características categóricas, como los meses, se representan mejor utilizando un gráfico de barras 📊. Las capas responsables de los gráficos de barras son `geom_bar()` y `geom_col()`. Consulta `?geom_bar` para obtener más información.\n",
"\n",
"¡Vamos a crear uno!\n"
],
"metadata": {
"id": "Kds48GUBcj3W"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Find the average price of pumpkins per month then plot a bar chart\r\n",
"new_pumpkins %>%\r\n",
" group_by(Month) %>% \r\n",
" summarise(mean_price = mean(Price)) %>% \r\n",
" ggplot(aes(x = Month, y = mean_price)) +\r\n",
" geom_col(fill = \"midnightblue\", alpha = 0.7) +\r\n",
" ylab(\"Pumpkin Price\")"
],
"outputs": [],
"metadata": {
"id": "VNbU1S3BcrxO"
}
},
{
"cell_type": "markdown",
"source": [
"🤩🤩¡Esta es una visualización de datos más útil! Parece indicar que el precio más alto de las calabazas ocurre en septiembre y octubre. ¿Cumple eso con tus expectativas? ¿Por qué sí o por qué no?\n",
"\n",
"¡Felicidades por terminar la segunda lección 👏! ¡Preparaste tus datos para la construcción del modelo y luego descubriste más información utilizando visualizaciones!\n"
],
"metadata": {
"id": "zDm0VOzzcuzR"
}
},
{
"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"
]
}
]
}