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.
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.
Antes de programar, es necesario instalar el software fundamental para el manejo de código y control de versiones.
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"
Descargue la versión estable más reciente desde python.org.
En Windows: Durante la instalación, marque obligatoriamente la casilla “Add Python.exe to PATH” en la parte inferior de la ventana inicial.
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.
Verifique la instalación en la terminal:
python --version # En Windows
python3 --version # En macOS/LinuxPara desarrollar en Python y desplegar aplicaciones con Streamlit, se requiere un conjunto específico 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.
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).
Esta fase es crítica para aislar las dependencias de sus proyectos y evitar conflictos entre librerías.
Cree una carpeta en su computador para el proyecto (ej.
Outliers_App).
Abra VSCode, vaya a File > Open Folder y
seleccione la carpeta creada.
Abra la terminal integrada en VSCode
(Terminal > New Terminal o
Ctrl+`).
Cree el entorno virtual ejecutando:
# En Windows
python -m venv .venv
# En macOS/Linux
python3 -m venv .venvActive 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.
requirements.txtCon 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
.gitignoreEl 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 ```
Una vez estructurado el proyecto, se debe vincular con un repositorio remoto en GitHub.
estadistica-outliers-app)..gitignore o licencia (ya lo haremos desde su portátil para
evitar conflictos de historial)..git).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
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:
source .venv/bin/activate o
.venv\Scripts\activate) antes de instalar nuevas librerías
o ejecutar su código.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.requirements.txt para instalar las dependencias en sus
servidores.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).
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.
El uso de Posit Cloud garantiza que todos los estudiantes partan de un entorno idéntico, eliminando problemas de compatibilidad de sistemas operativos.
Analisis_Outliers_App.Tools > Project Options >
Git/SVN.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.
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).
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).server):
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%).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%).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).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.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)
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.
app.R y .Rproj."Initial commit: Shiny app for outlier analysis with IQR logic".https://github.com/usuario/analisis-outliers.git).origin. URL: Pegue la URL copiada. Haga clic en
Add.rsconnect::setAccountInfo(...)).app.R esté abierto en el
editor.outliers-app-justo) y haga clic en
Publish.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”.
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.
Antes de iniciar el desarrollo, es necesario contar con las herramientas fundamentales de programación en R.
R.version.string
para confirmar que la instalación fue exitosa.El uso de Proyectos en RStudio (.Rproj) es una práctica
obligatoria para aislar las dependencias y rutas de archivos,
garantizando la reproducibilidad.
File > New Project > New Directory > Shiny Web Application.Analisis_Outliers_App).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
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.
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.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.%>% o |>), nombres de variables
descriptivos y comentarios detallados.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)
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.
rsconnect::setAccountInfo(...)).app.R abierto en el editor, haga clic en
el botón azul “Publish” en la esquina superior derecha
del panel de edición.https://su-usuario.shinyapps.io/Analisis_Outliers_App/).El repositorio debe ser público y estar organizado para obtener la calificación máxima en la rúbrica.
app.R y .Rproj
(marque las casillas en la columna “Staged”).
.gitignore
(creado automáticamente al iniciar el proyecto) esté excluyendo carpetas
como .Rproj.user/ o .Rhistory."Initial commit: Shiny app for outlier analysis with IQR logic".origin y
guarde.tryCatch, no colgarse.c(10, 12, 13, 14, 15, 16, 17, 18, 50, 150)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.