Estimado profesor Justo,

A continuación, se presenta la guía técnica detallada, estructurada en formato Markdown, diseñada para ser entregada a sus estudiantes de Ingeniería. Esta guía cubre la instalación, configuración y vinculación con GitHub, enfocándose en la opción de desarrollo con Python y Streamlit, asegurando que sus portátiles estén optimizados para futuros proyectos de analítica de datos.


Guía de Configuración del Entorno de Desarrollo para Analítica de Datos

Esta guía establece los pasos estándar para configurar un entorno de desarrollo profesional en su portátil. El objetivo es garantizar la reproducibilidad de sus proyectos, el control de versiones y el cumplimiento de las mejores prácticas de la industria.

Fase 1: Instalación de Herramientas Base

Antes de programar, es necesario instalar el software fundamental para el manejo de código y control de versiones.

1.1. Instalación de Git

Git es el sistema de control de versiones distribuido estándar. 1. Descargue el instalador desde el sitio oficial: git-scm.com. 2. Ejecute el instalador. Importante: Durante la instalación, mantenga las opciones por defecto. En Windows, asegúrese de seleccionar la opción que integra Git con la terminal de VSCode. 3. Verifique la instalación abriendo su terminal (CMD/PowerShell en Windows, o Terminal en macOS/Linux) y ejecute: bash git --version 4. Configure su identidad global (use el mismo correo de su cuenta de GitHub): bash git config --global user.name "Su Nombre Completo" git config --global user.email "su_correo@ejemplo.com"

1.2. Instalación de Python

  1. Descargue la versión estable más reciente desde python.org.

  2. En Windows: Durante la instalación, marque obligatoriamente la casilla “Add Python.exe to PATH” en la parte inferior de la ventana inicial.

  3. En macOS/Linux: Se recomienda instalar Python mediante el gestor de paquetes del sistema (ej. brew install python en Mac o sudo apt install python3 python3-venv python3-pip en Ubuntu) o usar el instalador oficial.

  4. Verifique la instalación en la terminal:

    python --version   # En Windows
    python3 --version  # En macOS/Linux

1.3. Instalación de Visual Studio Code (VSCode)

  1. Descargue e instale VSCode desde code.visualstudio.com.
  2. Ábralo y familiarícese con la barra lateral de actividades (Explorador, Búsqueda, Control de código fuente, Extensiones).

Fase 2: Configuración de VSCode y Extensiones

Para desarrollar en Python y desplegar aplicaciones con Streamlit, se requiere un conjunto específico de extensiones.

2.1. Instalación de Extensiones

Vaya a la pestaña de Extensiones (Ctrl+Shift+X o Cmd+Shift+X) e instale las siguientes extensiones oficiales: 1. Python (Microsoft): Soporte principal para el lenguaje. 2. Pylance (Microsoft): Motor de lenguajes para autocompletado rápido y verificación de tipos. 3. Streamlit (Streamlit): Soporte oficial para la ejecución y visualización de apps de Streamlit. 4. GitLens (GitKraken): Mejora las capacidades de Git, mostrando el historial de cambios línea por línea. 5. Jupyter (Microsoft): Útil para la exploración de datos y estadística aplicada.

2.2. Configuración del Editor (Buenas Prácticas PEP 8)

Para mantener el código limpio y estandarizado: 1. Abra la configuración (Ctrl+, o Cmd+,). 2. Busque Format On Save y márquelo (esto formateará el código automáticamente al guardar). 3. Busque Default Formatter y seleccione Black o autopep8 (si le pide instalar Black, acéptelo). 4. Busque Editor: Tab Size y asegúrese de que esté en 4 (estándar PEP 8 para Python).


Fase 3: Configuración del Entorno de Trabajo

Esta fase es crítica para aislar las dependencias de sus proyectos y evitar conflictos entre librerías.

3.1. Creación del Proyecto y Entorno Virtual (.venv)

  1. Cree una carpeta en su computador para el proyecto (ej. Outliers_App).

  2. Abra VSCode, vaya a File > Open Folder y seleccione la carpeta creada.

  3. Abra la terminal integrada en VSCode (Terminal > New Terminal o Ctrl+`).

  4. Cree el entorno virtual ejecutando:

    # En Windows
    python -m venv .venv
    
    # En macOS/Linux
    python3 -m venv .venv
  5. Active el entorno virtual:

    # En Windows (PowerShell)
    .venv\Scripts\activate
    
    # En Windows (CMD)
    .venv\Scripts\activate.bat
    
    # En macOS/Linux
    source .venv/bin/activate

    Nota: Sabrá que está activado cuando vea (.venv) al inicio de la línea de su terminal.

3.2. Instalación de Dependencias y requirements.txt

Con el entorno activado, instale las librerías necesarias para la actividad estadística y Streamlit:

pip install streamlit pandas numpy matplotlib plotly

Genere el archivo requirements.txt que documenta las versiones exactas de las librerías instaladas:

pip freeze > requirements.txt

3.3. Creación del archivo .gitignore

El archivo .gitignore le indica a Git qué archivos o carpetas ignorar (para no subir código basura o datos sensibles al repositorio). 1. Cree un archivo llamado .gitignore en la raíz de su proyecto (sin extensión). 2. Agregue el siguiente contenido estándar para Python: ```text # Entorno virtual .venv/ venv/ ENV/

# Archivos compilados de Python pycache/ .py[cod] $py.class

# Configuraciones locales de Streamlit .streamlit/secrets.toml

# Archivos de sistema .DS_Store Thumbs.db

# Archivos de datos locales (si no desea subirlos a GitHub) # .csv # .txt ```


Fase 4: Vinculación con GitHub y Despliegue Inicial

Una vez estructurado el proyecto, se debe vincular con un repositorio remoto en GitHub.

4.1. Creación del Repositorio en GitHub

  1. Inicie sesión en GitHub.com.
  2. Haga clic en el botón “+” (arriba a la derecha) y seleccione “New repository”.
  3. Nombre el repositorio (ej. estadistica-outliers-app).
  4. NO marque las opciones de inicializar con README, .gitignore o licencia (ya lo haremos desde su portátil para evitar conflictos de historial).
  5. Haga clic en “Create repository”.
  6. Copie la URL del repositorio (termina en .git).

4.2. Comandos de Terminal para Sincronización

En la terminal de VSCode (asegúrese de que el .venv esté activado y que el .gitignore y requirements.txt estén creados), ejecute los siguientes comandos en orden:

# 1. Inicializar el repositorio local de Git
git init

# 2. Agregar todos los archivos al área de preparación (respetando el .gitignore)
git add .

# 3. Realizar el primer commit (confirmación de cambios)
git commit -m "Initial commit: setup environment, requirements and gitignore"

# 4. Renombrar la rama principal a 'main' (estándar actual de GitHub)
git branch -M main

# 5. Vincular el repositorio local con el remoto (reemplace la URL con la suya)
git remote add origin https://github.com/SU_USUARIO/estadistica-outliers-app.git

# 6. Subir (push) los cambios al repositorio remoto
git push -u origin main

Fase 5: Recomendaciones para Futuros Desarrollos

Para garantizar el éxito en las próximas actividades de la asignatura y en su formación como ingenieros, tenga en cuenta las siguientes directrices:

  1. Flujo de Trabajo Diario: Siempre active su entorno virtual (source .venv/bin/activate o .venv\Scripts\activate) antes de instalar nuevas librerías o ejecutar su código.
  2. Actualización de requirements.txt: Si en el futuro instala una nueva librería (ej. pip install scipy), debe volver a ejecutar pip freeze > requirements.txt y subir los cambios a GitHub para mantener la reproducibilidad.
  3. Despliegue en la Nube: Una vez que su aplicación en Streamlit esté funcionando localmente, podrá conectar su repositorio de GitHub directamente a Streamlit Community Cloud. La plataforma leerá automáticamente su archivo requirements.txt para instalar las dependencias en sus servidores.
  4. Modularidad: A medida que su código crezca, separe la lógica de cálculo estadístico (funciones puras de Python) de la interfaz gráfica (código de Streamlit). Esto facilitará el mantenimiento y las pruebas unitarias.

Nota para el estudiante: Si decide optar por la ruta de R (Shiny App), los pasos de Git y GitHub (Fases 1 y 4) son exactamente los mismos. Sin embargo, en lugar de Python y VSCode, deberá instalar R, RStudio, y utilizar la terminal de RStudio para gestionar sus paquetes (install.packages()) y generar el archivo renv.lock (equivalente a requirements.txt en R).


Guía de Desarrollo en Posit Cloud: Shiny App para Análisis de Outliers (Opción R)

A continuación, se presenta la guía técnica detallada y adaptada exclusivamente para el entorno Posit Cloud (anteriormente RStudio Cloud). Esta versión elimina la necesidad de instalaciones locales, permitiendo que sus estudiantes de Ingeniería trabajen directamente desde el navegador, garantizando la reproducibilidad y cumpliendo con todos los criterios de la rúbrica de evaluación.

Esta guía establece el flujo de trabajo paso a paso para desarrollar, versionar y desplegar una aplicación web estadística en R, utilizando la infraestructura en la nube de Posit.

Fase 1: Acceso y Configuración del Proyecto en Posit Cloud

El uso de Posit Cloud garantiza que todos los estudiantes partan de un entorno idéntico, eliminando problemas de compatibilidad de sistemas operativos.

  1. Creación de la Cuenta:
    • Ingrese a posit.cloud e inicie sesión (puede usar su cuenta de GitHub o crear una nueva con su correo institucional).
  2. Creación del Proyecto:
    • En el panel principal, haga clic en “New Project” (esquina superior derecha).
    • Seleccione “Shiny App”.
    • Asigne un nombre al proyecto, por ejemplo: Analisis_Outliers_App.
    • Haga clic en “Create Project”. Se abrirá un entorno de RStudio completo en su navegador.
  3. Habilitación de Git (Control de Versiones):
    • En el menú superior del entorno Posit Cloud, vaya a Tools > Project Options > Git/SVN.
    • Marque la casilla “Enable version control”.
    • Haga clic en “OK”. El sistema reiniciará la sesión de Git y aparecerá la pestaña Git en el panel superior derecho.

Fase 2: Instalación de Paquetes Requeridos

En la Consola de Posit Cloud (panel inferior izquierdo), ejecute el siguiente bloque de código para instalar las librerías necesarias. Esto cumple con el estándar de estilo Tidyverse y prepara el entorno para el despliegue.

# Instalación de paquetes esenciales para la aplicación y el despliegue
install.packages(c("shiny", "tidyverse", "readr", "rsconnect", "bslib"))

Nota: bslib se incluye para aplicar un tema visual moderno y profesional a la interfaz de usuario.


Fase 3: Desarrollo del Código Base (app.R)

Reemplace todo el contenido del archivo app.R que Posit Cloud genera por defecto con el siguiente código. Este código ha sido diseñado para cumplir estrictamente con el Prompt de Ingeniería y la rúbrica de evaluación (RAE 1, 2 y 3).

Explicación de la Estructura y Funcionamiento del Código

  • Interfaz de Usuario (ui): Utiliza fluidPage y sidebarLayout para una distribución responsiva. Incluye un tabsetPanel que permite al usuario elegir entre ingreso manual de datos (separados por comas) o carga de archivos (CSV/TXT).
  • Lógica del Servidor (server):
    • Manejo de Excepciones: Utiliza tryCatch y validate(need(...)) para interceptar errores. Si el usuario ingresa letras, deja el campo vacío o proporciona menos de 4 datos, la aplicación muestra una notificación de error controlada en lugar de colapsar (Criterio de Interactividad: 25%).
    • Cálculo Estadístico: Un bloque reactive calcula Q1, Q2 (Mediana), Q3 e IQR. Clasifica los outliers en Moderados (fuera de 1.5 * IQR) y Extremos (fuera de 3.0 * IQR), cumpliendo el RAE 1 (30%).
    • Análisis de Impacto: Genera un data.frame dinámico que compara la Media y la Desviación Estándar con y sin outliers, calculando el porcentaje de variación de la desviación estándar (RAE 2).
    • Visualización: Utiliza ggplot2 con geom_boxplot y geom_jitter para superponer los puntos de datos, coloreando específicamente los outliers moderados (naranja) y extremos (rojo) para una identificación visual inmediata.

Código app.R

# ==============================================================================
# Aplicación Shiny: Análisis Estadístico y Detección de Outliers
# Asignatura: Estadística Aplicada con Python y R
# Descripción: Calcula cuartiles, IQR, clasifica outliers (moderados/extremos) 
#              y evalúa su impacto en la media y desviación estándar.
# ==============================================================================

library(shiny)
library(tidyverse)
library(readr)
library(bslib)

# ------------------------------------------------------------------------------
# INTERFAZ DE USUARIO (UI)
# ------------------------------------------------------------------------------
ui <- fluidPage(
  theme = bs_theme(version = 5, bootswatch = "flatly"),
  
  titlePanel("Diagnóstico Estadístico de Valores Atípicos (Outliers)"),
  
  sidebarLayout(
    sidebarPanel(
      h4("1. Ingreso de Datos"),
      tabsetPanel(
        tabPanel("Ingreso Manual",
                 textInput("datos_texto", "Ingrese números separados por comas:", 
                           placeholder = "Ej: 12, 15, 14, 50, 13, 100"),
                 actionButton("btn_manual", "Procesar Datos", class = "btn-primary")
        ),
        tabPanel("Cargar Archivo",
                 fileInput("archivo_csv", "Seleccione un archivo CSV o TXT", 
                           accept = c(".csv", ".txt", ".text")),
                 actionButton("btn_archivo", "Procesar Archivo", class = "btn-primary")
        )
      ),
      hr(),
      helpText("Nota: Se requieren al menos 4 datos numéricos válidos para el cálculo de cuartiles.")
    ),
    
    mainPanel(
      h4("2. Resultados Estadísticos"),
      verbatimTextOutput("resumen_cuartiles"),
      verbatimTextOutput("clasificacion_outliers"),
      
      h4("3. Análisis de Impacto"),
      tableOutput("tabla_impacto"),
      
      h4("4. Visualización"),
      plotOutput("boxplot_dinamico", height = "400px")
    )
  )
)

# ------------------------------------------------------------------------------
# LÓGICA DEL SERVIDOR (SERVER)
# ------------------------------------------------------------------------------
server <- function(input, output, session) {
  
  # 1. REACTIVIDAD: Ingesta y validación de datos
  datos_reactivos <- reactive({
    # Evitar ejecución automática al iniciar la app
    if (input$btn_manual == 0 && is.null(input$archivo_csv)) {
      return(NULL)
    }
    
    tryCatch({
      if (input$btn_manual > 0) {
        # Procesar entrada manual
        vector_crudo <- str_split(input$datos_texto, ",")[[1]] %>% str_trim()
        datos_num <- as.numeric(vector_crudo)
      } else {
        # Procesar archivo cargado
        req(input$archivo_csv)
        datos_crudos <- read_csv(input$archivo_csv$datapath, col_names = FALSE) %>% pull(1)
        datos_num <- as.numeric(datos_crudos)
      }
      
      # Manejo de excepciones: Validar que sean numéricos y suficientes
      validate(
        need(!any(is.na(datos_num)), "Error: Se detectaron valores no numéricos. Verifique su entrada.")
      )
      validate(
        need(length(datos_num) >= 4, "Error: Se requieren al menos 4 datos numéricos para calcular cuartiles e IQR.")
      )
      
      return(sort(datos_num, na.last = NA)) # Ordenar y eliminar NAs residuales
      
    }, error = function(e) {
      showNotification(e$message, type = "error", duration = 5)
      return(NULL)
    })
  })
  
  # 2. REACTIVIDAD: Cálculos Estadísticos y Clasificación
  estadisticas <- reactive({
    req(datos_reactivos())
    datos <- datos_reactivos()
    
    # Cálculo de Cuartiles (R usa el tipo 7 por defecto, manejando posiciones decimales)
    q1 <- quantile(datos, 0.25, names = FALSE)
    q2 <- quantile(datos, 0.50, names = FALSE) # Mediana
    q3 <- quantile(datos, 0.75, names = FALSE)
    iqr <- q3 - q1
    
    # Límites para Outliers Moderados (1.5 * IQR)
    lim_inf_mod <- q1 - 1.5 * iqr
    lim_sup_mod <- q3 + 1.5 * iqr
    
    # Límites para Outliers Extremos (3.0 * IQR)
    lim_inf_ext <- q1 - 3.0 * iqr
    lim_sup_ext <- q3 + 3.0 * iqr
    
    # Clasificación
    outliers_extremos <- datos[datos < lim_inf_ext | datos > lim_sup_ext]
    # Los moderados son los que están fuera de 1.5 IQR, pero NO son extremos
    outliers_moderados <- datos[(datos < lim_inf_mod | datos > lim_sup_mod) & 
                                !(datos %in% outliers_extremos)]
    
    # Datos limpios (sin NINGÚN outlier, es decir, dentro de 1.5 IQR)
    datos_limpios <- datos[datos >= lim_inf_mod & datos <= lim_sup_mod]
    
    list(
      datos_originales = datos,
      datos_limpios = datos_limpios,
      q1 = q1, q2 = q2, q3 = q3, iqr = iqr,
      mod = outliers_moderados,
      ext = outliers_extremos
    )
  })
  
  # 3. RENDERIZADO: Resumen de Cuartiles
  output$resumen_cuartiles <- renderPrint({
    req(estadisticas())
    stats <- estadisticas()
    cat(sprintf("Q1 (25%%): %.4f\n", stats$q1))
    cat(sprintf("Q2 / Mediana (50%%): %.4f\n", stats$q2))
    cat(sprintf("Q3 (75%%): %.4f\n", stats$q3))
    cat(sprintf("Rango Intercuartil (IQR): %.4f\n", stats$iqr))
  })
  
  # 4. RENDERIZADO: Clasificación de Outliers
  output$clasificacion_outliers <- renderPrint({
    req(estadisticas())
    stats <- estadisticas()
    
    cat("--- Outliers Extremos (> 3.0 * IQR) ---\n")
    if (length(stats$ext) == 0) {
      cat("No se detectaron valores atípicos extremos.\n")
    } else {
      cat(paste(stats$ext, collapse = ", "), "\n")
    }
    
    cat("\n--- Outliers Moderados (1.5 * IQR a 3.0 * IQR) ---\n")
    if (length(stats$mod) == 0) {
      cat("No se detectaron valores atípicos moderados.\n")
    } else {
      cat(paste(stats$mod, collapse = ", "), "\n")
    }
  })
  
  # 5. RENDERIZADO: Tabla de Impacto Estadístico
  output$tabla_impacto <- renderTable({
    req(estadisticas())
    stats <- estadisticas()
    
    # Cálculos con outliers
    media_con <- mean(stats$datos_originales)
    sd_con <- sd(stats$datos_originales)
    
    # Cálculos sin outliers (usando datos_limpios)
    if (length(stats$datos_limpios) < 2) {
      media_sin <- NA
      sd_sin <- NA
      pct_cambio_sd <- NA
    } else {
      media_sin <- mean(stats$datos_limpios)
      sd_sin <- sd(stats$datos_limpios)
      pct_cambio_sd <- ((sd_sin - sd_con) / sd_con) * 100
    }
    
    data.frame(
      Metrica = c("Media (Promedio)", "Desviación Estándar"),
      `Con Outliers` = c(round(media_con, 4), round(sd_con, 4)),
      `Sin Outliers` = c(round(media_sin, 4), round(sd_sin, 4)),
      `Variación % (SD)` = c(NA, round(pct_cambio_sd, 2)),
      check.names = FALSE
    )
  }, caption = "Comparativa de Métricas de Tendencia Central y Dispersión")
  
  # 6. RENDERIZADO: Gráfico de Caja y Bigotes (Boxplot)
  output$boxplot_dinamico <- renderPlot({
    req(estadisticas())
    stats <- estadisticas()
    
    df_plot <- data.frame(
      Valor = stats$datos_originales,
      Tipo = case_when(
        stats$datos_originales %in% stats$ext ~ "Extremo",
        stats$datos_originales %in% stats$mod ~ "Moderado",
        TRUE ~ "Normal"
      )
    )
    
    ggplot(df_plot, aes(x = "Datos", y = Valor, color = Tipo)) +
      geom_boxplot(fill = "lightblue", alpha = 0.5, outlier.shape = NA) + 
      geom_jitter(width = 0.1, size = 3, alpha = 0.8) + 
      scale_color_manual(values = c("Normal" = "black", "Moderado" = "orange", "Extremo" = "red")) +
      labs(
        title = "Distribución de Datos y Detección de Outliers",
        subtitle = "Puntos coloreados según su clasificación (Normal, Moderado, Extremo)",
        y = "Valor Numérico",
        x = ""
      ) +
      theme_minimal() +
      theme(legend.position = "bottom")
  })
}

# Ejecución de la aplicación
shinyApp(ui = ui, server = server)

Fase 4: Control de Versiones con GitHub desde Posit Cloud

Para obtener la calificación máxima en el criterio de “Calidad de Código y Estructura” (15%) y “Despliegue” (15%), el código debe estar versionado.

  1. En el panel superior derecho de Posit Cloud, haga clic en la pestaña Git.
  2. Haga clic en el botón Commit. Se abrirá una ventana con los archivos modificados.
  3. Marque las casillas en la columna Staged para los archivos app.R y .Rproj.
  4. En el campo “Commit message”, escriba: "Initial commit: Shiny app for outlier analysis with IQR logic".
  5. Haga clic en el botón Commit.
  6. Para vincularlo a GitHub:
    • Abra una nueva pestaña en su navegador, inicie sesión en GitHub.com y cree un New Repository (vacío, sin README, .gitignore ni licencia).
    • Copie la URL del repositorio (ej. https://github.com/usuario/analisis-outliers.git).
    • De vuelta en Posit Cloud, en la ventana de Git, haga clic en More (engranaje) > Remotes > Add.
    • Nombre: origin. URL: Pegue la URL copiada. Haga clic en Add.
  7. Finalmente, haga clic en el botón verde Push en la ventana de Commit para subir su código a GitHub.

Fase 5: Despliegue en shinyapps.io desde Posit Cloud

  1. Obtención del Token:
    • Inicie sesión en shinyapps.io.
    • Haga clic en su nombre (esquina superior derecha) > Tokens > Show.
  2. Vinculación en Posit Cloud:
    • Copie el bloque de código que aparece (inicia con rsconnect::setAccountInfo(...)).
    • Péguelo en la Consola de Posit Cloud y presione Enter. Esto vincula su espacio de trabajo en la nube con su cuenta de despliegue.
  3. Publicación:
    • Asegúrese de que el archivo app.R esté abierto en el editor.
    • En la parte superior derecha del panel de edición, haga clic en el botón azul Publish.
    • Seleccione “shinyapps.io”, asigne un nombre a la aplicación (ej. outliers-app-justo) y haga clic en Publish.
    • Posit Cloud instalará las dependencias en sus servidores y le proporcionará una URL pública al finalizar.

Fase 6: Conjunto de Datos de Prueba Oficial (Para el Estudiante)

Para garantizar que todos los estudiantes evalúen su aplicación bajo las mismas condiciones y puedan redactar su conclusión analítica (15% de la rúbrica), proporcione este conjunto de datos:

Opción A: Ingreso Manual (Copia y pega en la app)

12, 14, 15, 15, 16, 17, 18, 19, 20, 55, 120

Resultado esperado: - 55 será clasificado como Outlier Moderado. - 120 será clasificado como Outlier Extremo. - La desviación estándar debería mostrar una variación porcentual negativa significativa (reducción) al filtrar estos valores, lo que el estudiante debe explicar en su conclusión basándose en la sensibilidad de la fórmula de la desviación estándar a los valores alejados de la media.

Opción B: Archivo CSV Instruya a los estudiantes para crear un archivo llamado datos_prueba.csv con una sola columna de números idéntica a la lista anterior, y probar la pestaña “Cargar Archivo”.

Guía de Configuración y Desarrollo (LOCAL): Shiny App para Análisis de Outliers (Opción R)

Esta guía establece el flujo de trabajo estándar para desarrollar, documentar y desplegar una aplicación web estadística en R. El objetivo es garantizar la reproducibilidad, la limpieza del código y el cumplimiento de los Resultados de Aprendizaje Esperados (RAE) de la asignatura.

Fase 1: Instalación del Entorno Base

Antes de iniciar el desarrollo, es necesario contar con las herramientas fundamentales de programación en R.

  1. Instalación de R:
  2. Instalación de RStudio (IDE):
    • Descargue e instale RStudio Desktop (versión gratuita) desde posit.co/downloads. RStudio proporciona un entorno integrado esencial para el desarrollo de Shiny.
  3. Verificación:
    • Abra RStudio. En la consola, ejecute R.version.string para confirmar que la instalación fue exitosa.

Fase 2: Configuración del Proyecto y Paquetes

El uso de Proyectos en RStudio (.Rproj) es una práctica obligatoria para aislar las dependencias y rutas de archivos, garantizando la reproducibilidad.

2.1. Creación del Proyecto

  1. En RStudio, vaya a File > New Project > New Directory > Shiny Web Application.
  2. Nombre el directorio (ej. Analisis_Outliers_App).
  3. Marque la casilla “Use git for version control” (esto inicializará el repositorio local de Git automáticamente).
  4. Haga clic en Create Project.

2.2. Instalación de Paquetes Requeridos

En la consola de RStudio, ejecute el siguiente bloque de código para instalar las librerías necesarias. Estas se alinean con la guía de estilo Tidyverse y los requisitos de despliegue.

# Instalación de paquetes esenciales para la aplicación
install.packages(c("shiny", "tidyverse", "readr", "ggplot2", "rsconnect"))

# Nota: 'rsconnect' es el paquete oficial de Posit para desplegar en shinyapps.io

Fase 3: Código Base de la Aplicación Shiny

A continuación, se proporciona el código base estructurado, modular y documentado que cumple con el Prompt de Ingeniería de la actividad. Reemplace el contenido del archivo app.R generado por RStudio con este código.

Explicación de la Estructura del Código

  • UI (Interfaz de Usuario): Utiliza fluidPage y sidebarLayout para una distribución responsiva. Incluye controles para entrada manual (texto) o carga de archivos (CSV), y un botón para activar el procesamiento.
  • Server (Lógica del Servidor):
    • reactive({}): Maneja la ingesta y validación de datos, asegurando que se ingresen al menos 4 valores numéricos (manejo de excepciones).
    • calculos_estadisticos: Un bloque reactivo que calcula cuartiles, IQR y clasifica los outliers en moderados (1.5 * IQR) y extremos (3.0 * IQR).
    • tabla_impacto: Genera la comparación de Media y Desviación Estándar (con y sin outliers), calculando el porcentaje de cambio en la desviación.
    • renderPlot: Genera un Boxplot dinámico con ggplot2, resaltando visualmente los puntos atípicos.
  • Buenas Prácticas: El código utiliza el operador pipe (%>% o |>), nombres de variables descriptivos y comentarios detallados.

Código app.R

# ==============================================================================
# Aplicación Shiny: Análisis Estadístico y Detección de Outliers
# Asignatura: Estadística Aplicada con Python y R
# Descripción: Calcula cuartiles, IQR, clasifica outliers (moderados/extremos) 
#              y evalúa su impacto en la media y desviación estándar.
# ==============================================================================

library(shiny)
library(tidyverse)
library(readr)

# ------------------------------------------------------------------------------
# INTERFAZ DE USUARIO (UI)
# ------------------------------------------------------------------------------
ui <- fluidPage(
  theme = bslib::bs_theme(version = 5, bootswatch = "flatly"), # Estilo moderno
  
  titlePanel("Diagnóstico Estadístico de Valores Atípicos (Outliers)"),
  
  sidebarLayout(
    sidebarPanel(
      h4("1. Ingreso de Datos"),
      tabsetPanel(
        tabPanel("Ingreso Manual",
                 textInput("datos_texto", "Ingrese números separados por comas:", 
                           placeholder = "Ej: 12, 15, 14, 50, 13, 100"),
                 actionButton("btn_manual", "Procesar Datos Manuales", class = "btn-primary")
        ),
        tabPanel("Cargar Archivo",
                 fileInput("archivo_csv", "Seleccione un archivo CSV o TXT", 
                           accept = c(".csv", ".txt")),
                 actionButton("btn_archivo", "Procesar Archivo", class = "btn-primary")
        )
      ),
      hr(),
      helpText("Nota: Se requieren al menos 4 datos numéricos válidos para el cálculo de cuartiles.")
    ),
    
    mainPanel(
      h4("2. Resultados Estadísticos"),
      verbatimTextOutput("resumen_cuartiles"),
      verbatimTextOutput("clasificacion_outliers"),
      
      h4("3. Análisis de Impacto"),
      tableOutput("tabla_impacto"),
      
      h4("4. Visualización"),
      plotOutput("boxplot_dinamico", height = "400px")
    )
  )
)

# ------------------------------------------------------------------------------
# LÓGICA DEL SERVIDOR (SERVER)
# ------------------------------------------------------------------------------
server <- function(input, output, session) {
  
  # 1. REACTIVIDAD: Ingesta y validación de datos
  datos_reactivos <- reactive({
    # Evitar ejecución al iniciar la app
    if (input$btn_manual == 0 && is.null(input$archivo_csv)) {
      return(NULL)
    }
    
    tryCatch({
      if (input$btn_manual > 0) {
        # Procesar entrada manual
        vector_crudo <- str_split(input$datos_texto, ",")[[1]] %>% str_trim()
        datos_num <- as.numeric(vector_crudo)
      } else {
        # Procesar archivo cargado
        req(input$archivo_csv)
        datos_crudos <- read_csv(input$archivo_csv$datapath, col_names = FALSE) %>% pull(1)
        datos_num <- as.numeric(datos_crudos)
      }
      
      # Manejo de excepciones: Validar que sean numéricos y suficientes
      if (any(is.na(datos_num))) {
        stop("Error: Se detectaron valores no numéricos. Verifique su entrada.")
      }
      if (length(datos_num) < 4) {
        stop("Error: Se requieren al menos 4 datos numéricos para calcular cuartiles e IQR.")
      }
      
      return(sort(datos_num)) # Ordenar para facilitar el análisis
      
    }, error = function(e) {
      showNotification(e$message, type = "error", duration = 5)
      return(NULL)
    })
  })
  
  # 2. REACTIVIDAD: Cálculos Estadísticos y Clasificación
  estadisticas <- reactive({
    req(datos_reactivos())
    datos <- datos_reactivos()
    
    # Cálculo de Cuartiles (R usa el tipo 7 por defecto, que maneja posiciones decimales)
    q1 <- quantile(datos, 0.25, names = FALSE)
    q2 <- quantile(datos, 0.50, names = FALSE) # Mediana
    q3 <- quantile(datos, 0.75, names = FALSE)
    iqr <- q3 - q1
    
    # Límites para Outliers Moderados (1.5 * IQR)
    lim_inf_mod <- q1 - 1.5 * iqr
    lim_sup_mod <- q3 + 1.5 * iqr
    
    # Límites para Outliers Extremos (3.0 * IQR)
    lim_inf_ext <- q1 - 3.0 * iqr
    lim_sup_ext <- q3 + 3.0 * iqr
    
    # Clasificación
    outliers_extremos <- datos[datos < lim_inf_ext | datos > lim_sup_ext]
    # Los moderados son los que están fuera de 1.5 IQR, pero NO son extremos
    outliers_moderados <- datos[(datos < lim_inf_mod | datos > lim_sup_mod) & 
                                !(datos %in% outliers_extremos)]
    
    # Datos limpios (sin NINGÚN outlier, es decir, dentro de 1.5 IQR)
    datos_limpios <- datos[datos >= lim_inf_mod & datos <= lim_sup_mod]
    
    list(
      datos_originales = datos,
      datos_limpios = datos_limpios,
      q1 = q1, q2 = q2, q3 = q3, iqr = iqr,
      mod = outliers_moderados,
      ext = outliers_extremos
    )
  })
  
  # 3. RENDERIZADO: Resumen de Cuartiles
  output$resumen_cuartiles <- renderPrint({
    req(estadisticas())
    stats <- estadisticas()
    cat(sprintf("Q1 (25%%): %.4f\n", stats$q1))
    cat(sprintf("Q2 / Mediana (50%%): %.4f\n", stats$q2))
    cat(sprintf("Q3 (75%%): %.4f\n", stats$q3))
    cat(sprintf("Rango Intercuartil (IQR): %.4f\n", stats$iqr))
  })
  
  # 4. RENDERIZADO: Clasificación de Outliers
  output$clasificacion_outliers <- renderPrint({
    req(estadisticas())
    stats <- estadisticas()
    
    cat("--- Outliers Extremos (> 3.0 * IQR) ---\n")
    if (length(stats$ext) == 0) {
      cat("No se detectaron valores atípicos extremos.\n")
    } else {
      cat(paste(stats$ext, collapse = ", "), "\n")
    }
    
    cat("\n--- Outliers Moderados (1.5 * IQR a 3.0 * IQR) ---\n")
    if (length(stats$mod) == 0) {
      cat("No se detectaron valores atípicos moderados.\n")
    } else {
      cat(paste(stats$mod, collapse = ", "), "\n")
    }
  })
  
  # 5. RENDERIZADO: Tabla de Impacto Estadístico
  output$tabla_impacto <- renderTable({
    req(estadisticas())
    stats <- estadisticas()
    
    # Cálculos con outliers
    media_con <- mean(stats$datos_originales)
    sd_con <- sd(stats$datos_originales)
    
    # Cálculos sin outliers (usando datos_limpios)
    # Validar que queden suficientes datos para calcular SD
    if (length(stats$datos_limpios) < 2) {
      media_sin <- NA
      sd_sin <- NA
      pct_cambio_sd <- NA
    } else {
      media_sin <- mean(stats$datos_limpios)
      sd_sin <- sd(stats$datos_limpios)
      pct_cambio_sd <- ((sd_sin - sd_con) / sd_con) * 100
    }
    
    data.frame(
      Metrica = c("Media (Promedio)", "Desviación Estándar"),
      `Con Outliers` = c(round(media_con, 4), round(sd_con, 4)),
      `Sin Outliers` = c(round(media_sin, 4), round(sd_sin, 4)),
      `Variación % (SD)` = c(NA, round(pct_cambio_sd, 2)),
      check.names = FALSE
    )
  }, caption = "Comparativa de Métricas de Tendencia Central y Dispersión")
  
  # 6. RENDERIZADO: Gráfico de Caja y Bigotes (Boxplot)
  output$boxplot_dinamico <- renderPlot({
    req(estadisticas())
    stats <- estadisticas()
    
    # Crear un data frame para ggplot
    df_plot <- data.frame(
      Valor = stats$datos_originales,
      Tipo = case_when(
        stats$datos_originales %in% stats$ext ~ "Extremo",
        stats$datos_originales %in% stats$mod ~ "Moderado",
        TRUE ~ "Normal"
      )
    )
    
    ggplot(df_plot, aes(x = "Datos", y = Valor, color = Tipo)) +
      geom_boxplot(fill = "lightblue", alpha = 0.5, outlier.shape = NA) + # Ocultar outliers por defecto de geom_boxplot
      geom_jitter(width = 0.1, size = 3, alpha = 0.8) + # Mostrar todos los puntos
      scale_color_manual(values = c("Normal" = "black", "Moderado" = "orange", "Extremo" = "red")) +
      labs(
        title = "Distribución de Datos y Detección de Outliers",
        subtitle = "Puntos coloreados según su clasificación (Normal, Moderado, Extremo)",
        y = "Valor Numérico",
        x = ""
      ) +
      theme_minimal() +
      theme(legend.position = "bottom")
  })
}

# Ejecución de la aplicación
shinyApp(ui = ui, server = server)

Fase 4: Despliegue en shinyapps.io

Para cumplir con el RAE 3 y el 15% de la rúbrica de “Despliegue y Acceso”, la aplicación debe estar en la nube.

  1. Creación de Cuenta: Regístrese de forma gratuita en shinyapps.io.
  2. Obtención de Credenciales:
    • En el panel de shinyapps.io, vaya a su nombre (esquina superior derecha) > Tokens > Show.
  3. Configuración en RStudio:
    • Copie el código que aparece en la pantalla de Tokens (se ve como rsconnect::setAccountInfo(...)).
    • Péguelo en la consola de RStudio y ejecútelo. Esto vincula su RStudio con su cuenta en la nube.
  4. Despliegue:
    • Con el archivo app.R abierto en el editor, haga clic en el botón azul “Publish” en la esquina superior derecha del panel de edición.
    • Seleccione su cuenta de shinyapps.io, asigne un nombre a la aplicación y haga clic en Publish.
    • RStudio subirá los archivos y le proporcionará una URL pública (ej. https://su-usuario.shinyapps.io/Analisis_Outliers_App/).

Fase 5: Control de Versiones con GitHub

El repositorio debe ser público y estar organizado para obtener la calificación máxima en la rúbrica.

  1. En RStudio, vaya a la pestaña Git (esquina superior derecha).
  2. Haga clic en Commit.
  3. Seleccione los archivos app.R y .Rproj (marque las casillas en la columna “Staged”).
    • Nota: Asegúrese de que su archivo .gitignore (creado automáticamente al iniciar el proyecto) esté excluyendo carpetas como .Rproj.user/ o .Rhistory.
  4. Escriba un mensaje de commit claro, ej: "Initial commit: Shiny app for outlier analysis with IQR logic".
  5. Haga clic en Commit.
  6. Para vincularlo a GitHub:
    • En GitHub, cree un New Repository (vacío, sin README).
    • Copie la URL del repositorio.
    • En RStudio, en la ventana de Git, haga clic en More > Remotes > Add.
    • Pegue la URL, nombre el remoto como origin y guarde.
    • Haga clic en el botón verde Push para subir su código a GitHub.

Recomendaciones Finales para el Estudiante

  1. Pruebas de Caja Blanca: Antes de desplegar, pruebe la aplicación ingresando deliberadamente letras, espacios vacíos o solo 3 números. La aplicación debe mostrar la notificación de error configurada en el tryCatch, no colgarse.
  2. Conjunto de Datos de Prueba: Se recomienda probar la app con el siguiente vector para validar la lógica de clasificación:
    c(10, 12, 13, 14, 15, 16, 17, 18, 50, 150)
    (Aquí, 50 debería ser moderado y 150 extremo, dependiendo del cálculo exacto del IQR, lo cual permite verificar la tabla de impacto).
  3. Análisis en la Entrega: En su documento final, no solo pegue los enlaces. Dedique el párrafo de conclusión a explicar por qué la desviación estándar disminuyó drásticamente al eliminar los valores extremos, relacionándolo con la fórmula matemática de la varianza (sensibilidad a valores alejados de la media).

Quedo a su entera disposición, profesor Justo, si requiere ajustar algún parámetro estadístico del código o generar el conjunto de datos de prueba oficial en formato CSV para distribuirlo junto con esta guía.