Cargar datos y analizar normalidad
library(shiny)
library(tidyverse)
library(DT)
library(ggplot2)
# UI
ui <- fluidPage(
# Titulo y estilo
tags$head(
tags$style(HTML("
.content-wrapper { padding: 20px; }
.box { border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
h2 { color: #2C3E50; }
"))
),
titlePanel("Análisis Exploratorio de Datos"),
sidebarLayout(
sidebarPanel(
# Input para cargar archivo
fileInput("file", "Sube un archivo CSV",
accept = c(".csv", ".tsv"),
buttonLabel = "Seleccionar...",
placeholder = "Ningún archivo seleccionado"),
# Opciones de lectura del archivo
checkboxInput("header", "¿El archivo tiene encabezado?", TRUE),
radioButtons("sep", "Separador:",
choices = c(Coma = ",", "Punto y coma" = ";", Tabulador = "\t"),
selected = ","),
# Selector de variables (se actualizará dinámicamente)
uiOutput("varselect"),
# Ajustes del histograma
sliderInput("bins", "Número de intervalos:", min = 5, max = 100, value = 30),
# Selector para prueba de normalidad
selectInput("normality_test", "Prueba de normalidad:",
choices = c("Shapiro-Wilk" = "shapiro",
"Kolmogorov-Smirnov" = "ks"),
selected = "shapiro"),
# Botón para generar análisis
actionButton("analyze", "Analizar Datos",
class = "btn-primary btn-block",
icon = icon("chart-bar"))
),
mainPanel(
tabsetPanel(
tabPanel("Resumen de datos",
h3("Vista previa de los datos"),
DTOutput("data_preview"),
hr(),
h3("Estadísticas descriptivas"),
verbatimTextOutput("summary"),
hr(),
h3("Prueba de normalidad"),
verbatimTextOutput("normality_result")),
tabPanel("Visualización",
fluidRow(
column(6, plotOutput("histplot")),
column(6, plotOutput("boxplot"))
),
hr(),
plotOutput("qq_plot")),
tabPanel("Información",
h3("Datos cargados"),
verbatimTextOutput("data_info"),
hr(),
h3("Variables detectadas"),
verbatimTextOutput("vars_info"))
)
)
)
)
# Server
server <- function(input, output, session) {
# Función reactiva para leer los datos
data <- reactive({
req(input$file)
# Leer el archivo según el separador seleccionado
read_delim(input$file$datapath,
delim = input$sep,
col_names = input$header,
show_col_types = FALSE)
})
# Generar selector de variables
output$varselect <- renderUI({
req(data())
num_vars <- names(select_if(data(), is.numeric))
if(length(num_vars) == 0) {
return(HTML("<div class='alert alert-warning'>No se detectaron variables numéricas</div>"))
}
selectInput("variable", "Selecciona una variable cuantitativa",
choices = num_vars,
selected = num_vars[1])
})
# Información de los datos
output$data_info <- renderPrint({
req(data())
cat("Nombre del archivo:", input$file$name, "\n")
cat("Dimensiones:", dim(data())[1], "filas x", dim(data())[2], "columnas\n")
cat("Tamaño del archivo:", round(input$file$size/1024, 2), "KB\n")
})
# Información de variables
output$vars_info <- renderPrint({
req(data())
str(data())
})
# Vista previa de los datos
output$data_preview <- renderDT({
req(data())
datatable(head(data(), 10), options = list(scrollX = TRUE))
})
# Todos los outputs se generan cuando se hace clic en "Analizar"
observeEvent(input$analyze, {
# Estadísticas descriptivas
output$summary <- renderPrint({
req(input$variable)
summary_stats <- data() %>%
summarise(
n = n(),
na = sum(is.na(.[[input$variable]])),
min = min(.[[input$variable]], na.rm = TRUE),
q1 = quantile(.[[input$variable]], 0.25, na.rm = TRUE),
median = median(.[[input$variable]], na.rm = TRUE),
mean = mean(.[[input$variable]], na.rm = TRUE),
q3 = quantile(.[[input$variable]], 0.75, na.rm = TRUE),
max = max(.[[input$variable]], na.rm = TRUE),
sd = sd(.[[input$variable]], na.rm = TRUE),
cv = sd(.[[input$variable]], na.rm = TRUE) / mean(.[[input$variable]], na.rm = TRUE) * 100,
iqr = IQR(.[[input$variable]], na.rm = TRUE),
skewness = moments::skewness(.[[input$variable]], na.rm = TRUE),
kurtosis = moments::kurtosis(.[[input$variable]], na.rm = TRUE)
)
print(summary_stats)
})
# Histograma
output$histplot <- renderPlot({
req(input$variable)
# Calcular densidad para superponer curva normal
var_data <- na.omit(data()[[input$variable]])
ggplot(data(), aes_string(x = input$variable)) +
geom_histogram(aes(y = ..density..), bins = input$bins,
fill = "#69b3a2", color = "black", alpha = 0.7) +
geom_density(color = "#e63946", linewidth = 1.2) +
stat_function(fun = dnorm,
args = list(mean = mean(var_data, na.rm = TRUE),
sd = sd(var_data, na.rm = TRUE)),
color = "#1d3557", linewidth = 1, linetype = "dashed") +
theme_minimal(base_size = 14) +
labs(title = paste("Distribución de", input$variable),
subtitle = "Con curva de densidad (rojo) y curva normal (azul)",
x = input$variable,
y = "Densidad") +
theme(plot.title = element_text(face = "bold"),
axis.title = element_text(face = "bold"))
})
# Boxplot
output$boxplot <- renderPlot({
req(input$variable)
ggplot(data(), aes_string(y = input$variable)) +
geom_boxplot(fill = "#457b9d", alpha = 0.7) +
coord_flip() +
theme_minimal(base_size = 14) +
labs(title = paste("Diagrama de caja de", input$variable),
subtitle = "Detección de valores atípicos",
x = "",
y = input$variable) +
theme(plot.title = element_text(face = "bold"),
axis.title = element_text(face = "bold"))
})
# QQ Plot
output$qq_plot <- renderPlot({
req(input$variable)
var_data <- na.omit(data()[[input$variable]])
ggplot(data.frame(x = var_data), aes(sample = x)) +
stat_qq() +
stat_qq_line(color = "#e63946") +
theme_minimal(base_size = 14) +
labs(title = paste("Gráfico Q-Q de", input$variable),
subtitle = "Evaluación visual de normalidad",
x = "Cuantiles teóricos",
y = "Cuantiles observados") +
theme(plot.title = element_text(face = "bold"),
axis.title = element_text(face = "bold"))
})
# Prueba de normalidad
output$normality_result <- renderPrint({
req(input$variable)
var_data <- na.omit(data()[[input$variable]])
if (length(var_data) < 3) {
cat("Se necesitan al menos 3 observaciones para realizar pruebas de normalidad.")
} else if (input$normality_test == "shapiro" && length(var_data) > 5000) {
cat("Shapiro-Wilk es apropiado para muestras de hasta 5000 observaciones.\n")
cat("Tu muestra tiene", length(var_data), "observaciones. Considera usar Kolmogorov-Smirnov.")
} else {
if (input$normality_test == "shapiro") {
resultado <- shapiro.test(var_data)
cat("Prueba de Shapiro-Wilk para normalidad\n\n")
} else {
resultado <- suppressWarnings(ks.test(var_data, "pnorm",
mean = mean(var_data),
sd = sd(var_data)))
cat("Prueba de Kolmogorov-Smirnov para normalidad\n\n")
}
print(resultado)
cat("\nInterpretación:\n")
if (resultado$p.value < 0.05) {
cat("Con un p-valor de", round(resultado$p.value, 4),
"hay evidencia para rechazar la hipótesis nula de normalidad.")
} else {
cat("Con un p-valor de", round(resultado$p.value, 4),
"no hay evidencia suficiente para rechazar la hipótesis de normalidad.")
}
}
})
})
}
# Ejecutar la aplicación
shinyApp(ui = ui, server = server)