El Principio MLOps: Desacoplar Lógica
En el desarrollo de software y MLOps, un principio fundamental es la **separación de responsabilidades**. Esto significa que cada pieza de nuestro sistema debe hacer una sola cosa y hacerla bien. Mezclar la lógica de preparación de datos con la lógica de la interfaz de usuario (la app Shiny) es una receta para el "spaghetti code": un sistema frágil, difícil de depurar y imposible de escalar.
Por eso, nuestro objetivo en esta lección no es solo aprender a usar `dplyr`. Es aprender a encapsular nuestras transformaciones de datos en un **artefacto**: un script de R (`.R`) autocontenido, versionable y reutilizable. Este script se convierte en un componente fundamental de nuestro pipeline de MLOps, que podremos probar de forma aislada y consumir desde nuestra aplicación Shiny o cualquier otro proceso.
La Herramienta: Verbos Esenciales de `dplyr`
Para construir nuestro artefacto de procesamiento, usaremos `dplyr`. Sus "verbos" nos permiten escribir pasos de transformación de datos que son tan legibles como una receta de cocina.
select() y filter()
                        `select()` elige columnas por su nombre. `filter()` elige filas basadas en una condición lógica.
# Selecciona solo las columnas de puntaje y filtra por colegios oficiales
datos_limpios <- datos_saber %>%
  select(starts_with("punt_"), cole_naturaleza) %>%
  filter(cole_naturaleza == "OFICIAL")mutate()
                        Crea nuevas columnas o modifica existentes. Es el corazón de la ingeniería de características (feature engineering).
# Crea una nueva columna que promedia los puntajes de ciencias y matemáticas
datos_enriquecidos <- datos_saber %>%
  mutate(promedio_ciencias_mat = (punt_ciencias_naturales + punt_matematicas) / 2)group_by() y summarise()
                        Trabajan juntos para realizar resúmenes agregados. `group_by()` define los grupos y `summarise()` calcula métricas para cada uno.
# Calcula el puntaje global promedio para cada tipo de colegio
resumen_por_naturaleza <- datos_saber %>%
  group_by(cole_naturaleza) %>%
  summarise(
    puntaje_promedio = mean(punt_global, na.rm = TRUE),
    total_estudiantes = n()
  )Guía Práctica: Construcción e Integración del Artefacto
Ahora que conocemos las herramientas, vamos a aplicar estos principios para crear nuestro primer artefacto de procesamiento y conectarlo a la aplicación, siguiendo la estructura de proyecto definida en el Módulo 1.
Paso 1: Ubicar el Artefacto en la Estructura del Proyecto
El primer paso es saber dónde vivirá nuestro nuevo componente. Según la arquitectura MLOps que establecimos, toda la lógica de R reutilizable (funciones de procesamiento, modelado, etc.) debe residir en la carpeta `/R`.
- mi-proyecto/
- data/
- R/
- data_processing.R <-- NUESTRO ARTEFACTO
- global.R
- server.R
- ui.R
Acción: En tu proyecto, dentro de la carpeta `/R`, crea un nuevo archivo llamado `data_processing.R`.
Paso 2: Desarrollar el Pipeline dentro de una Función
Ahora, escribimos el pipeline de `dplyr`. Es una práctica recomendada envolverlo en una función. Esto lo hace reutilizable y fácil de probar de forma independiente.
Acción: Abre `R/data_processing.R` y añade el siguiente código.
# Contenido del artefacto: R/data_processing.R
prepare_saber_data <- function(raw_data) {
  
  message("Ejecutando pipeline de preparación de datos...")
  
  processed_data <- raw_data %>%
    na.omit() %>%
    mutate(
      rendimiento_global = case_when(
        punt_global >= 350 ~ "Alto",
        punt_global >= 250 ~ "Medio",
        TRUE ~ "Bajo"
      )
    ) %>%
    select(
      starts_with("punt_"),
      cole_naturaleza,
      rendimiento_global
    )
    
  return(processed_data)
}
Paso 3: Integrar el Artefacto en la Aplicación
Nuestra aplicación Shiny ahora no procesará los datos directamente. En su lugar, actuará como un **consumidor** de nuestro artefacto. El punto de integración es el archivo `global.R`, que se ejecuta una sola vez al inicio de la aplicación y actúa como nuestro orquestador principal.
Acción: Modifica tu archivo `global.R` para que cargue el script del artefacto y lo utilice.
# En global.R
# ... (tus librerías: library(shiny), library(dplyr), etc.) ...
# 1. Cargar el artefacto de procesamiento de datos
source("R/data_processing.R")
# 2. Cargar los datos crudos
datos_crudos <- read_delim("data/raw/Examen_Saber_11_20242.txt", delim = ";", show_col_types = FALSE)
# 3. Ejecutar el pipeline para crear el dataframe limpio que usará la app
datos_saber <- prepare_saber_data(datos_crudos)
# ... (el resto de tu código de global.R) ...
El Nuevo Flujo de Datos MLOps
Con este cambio, hemos establecido un flujo claro y desacoplado:
- `global.R` actúa como orquestador: carga los datos crudos.
- Llama a la función desde nuestro artefacto (`R/data_processing.R`) para procesarlos.
- El resultado (datos_saber) es un dataframe limpio y listo para ser usado por la lógica reactiva en `server.R`.
Paso 4: Versionar el Nuevo Artefacto
Has creado un componente de software modular. Este es un hito importante en el ciclo de vida del proyecto y debe ser registrado en Git con un mensaje que refleje su importancia.
# Añade el nuevo artefacto y los cambios en el orquestador
git add R/data_processing.R global.R
# Un commit que describe la creación de un componente MLOps
git commit -m "feat(data): Crea artefacto de procesamiento de datos y lo integra en la app"
git push