1 Portada

Actividad: Simulación de variables aleatorias e Intervalos de Confianza (IC 95%).
Objetivo: Estimar y comparar IC del 95% para la media poblacional en dos escenarios (Normal y Exponencial) mediante simulación.
Parámetros del enunciado:
- Tiempos de atención: \(X \sim \mathcal{N}(\mu=15,\ \sigma=5)\) minutos.
- Tiempos entre llegadas: \(Y \sim \text{Exp}(\text{media}=3.5\ \text{min})\) \(\Rightarrow\) \(\text{rate}=1/3.5\).
- Réplicas \(R=30\); tamaño por réplica \(n=20\).

2 Resumen ejecutivo (8–12 líneas)

Se realizaron 30 réplicas independientes con \(n=20\) observaciones para cada escenario. En el escenario Normal se simularon tiempos de atención con \(\mu=15\) y \(\sigma=5\) minutos; en el escenario Exponencial se simularon tiempos entre llegadas con media 3.5 minutos (\(\text{rate}=1/3.5\)). Para cada réplica se calculó la media muestral y, con el conjunto de 30 medias por escenario, se construyó un IC del 95% para la media poblacional utilizando t-Student (varianza desconocida, \(R=30\)). Los histogramas, QQ-plots y boxplots de las medias por réplica evidencian aproximación a la normalidad (TCL), especialmente marcada en el caso Normal y razonable en Exponencial. Los IC se centran cerca de los valores verdaderos (15 y 3.5 minutos) y su amplitud concuerda con la variabilidad teórica de las medias (\(\sigma/\sqrt{n}\)). Las pruebas de normalidad (Shapiro-Wilk) y ajustes comparativos (Normal/Lognormal/Gamma) sobre las medias respaldan el uso de la Normal. La discusión incluye sensibilidad a \(n\) y \(R\) y una visualización de cobertura con IC por réplica.

3 Checklist de cumplimiento

Requisito del enunciado Evidencia (sección) Cumple Acción correctiva
Simular 30 réplicas × 20 obs. Normal(15,5); guardar media por réplica § Metodología / § Resultados (código y tablas)
Simular 30 réplicas × 20 obs. Exponencial(media=3.5); media por réplica § Metodología / § Resultados
IC 95% para media poblacional (t sobre 30 medias por réplica) § Resultados (Tabla resumen)
Histogramas, QQ-plots y boxplots de las medias por réplica § Gráficos
Comparación Normal vs. Exponencial e interpretación del IC § Análisis/Discusión
Ajuste tipo Stat:Fit (emulado en R) para medias § Ajuste/validación de distribución
Documento listo para Word/HTML YAML y este .Rmd
Apéndices: código íntegro, semillas, sessionInfo, tabla completa de 30 medias § Apéndices

4 Metodología de simulación

4.1 Código

# Paquetes
# -- Fijar espejo CRAN para evitar el error "trying to use CRAN without setting a mirror"
if (is.null(getOption("repos")) || getOption("repos")["CRAN"] %in% c(NULL, "@CRAN@", "")) {
  options(repos = c(CRAN = "https://cloud.r-project.org"))
}
req_pkgs <- c("ggplot2","dplyr","tibble","knitr","fitdistrplus")
to_install <- setdiff(req_pkgs, rownames(installed.packages()))
if (length(to_install) > 0) {
  try(install.packages(to_install, quiet = TRUE), silent = TRUE)
}
invisible(lapply(req_pkgs, function(p){
  if (!suppressWarnings(require(p, character.only = TRUE))) {
    stop(sprintf("No se pudo cargar el paquete '%s'. Instálalo manualmente: install.packages('%s')", p, p))
  }
}))

# Parámetros y semilla
set.seed(1234L)       # reproducibilidad
n      <- 20L         # tamaño por réplica
R      <- 30L         # número de réplicas
mu_n   <- 15          # Normal: media (min)
sd_n   <- 5           # Normal: desviación estándar (min)
mean_e <- 3.5         # Exponencial: media (min)
rate_e <- 1/mean_e    # Exponencial: rate
# Validación de parámetros para evitar NAs
stopifnot(is.finite(mean_e), mean_e > 0)
stopifnot(is.finite(rate_e), rate_e > 0)

# Carpeta de salida
out_dir <- "output"
if (!dir.exists(out_dir)) dir.create(out_dir, recursive = TRUE)

# Funciones auxiliares
ic95_t <- function(v) {
  stopifnot(is.numeric(v), length(v) >= 2)
  v <- v[!is.na(v)]
  m  <- mean(v); s <- sd(v); N <- length(v)
  se <- s / sqrt(N)
  tcrit <- qt(0.975, df = N - 1)
  c(LI = m - tcrit * se, LS = m + tcrit * se)
}

ic95_t_onerep <- function(x, alpha = 0.05) {
  stopifnot(is.numeric(x), length(x) >= 2)
  x <- x[!is.na(x)]
  n <- length(x); m <- mean(x); s <- sd(x)
  se <- s / sqrt(n)
  tcrit <- qt(1 - alpha/2, df = n - 1)
  c(LI = m - tcrit * se, LS = m + tcrit * se)
}

replicate_means <- function(R, n, gen_fun, ...) {
  replicate(R, mean(gen_fun(n, ...)))
}

coverage_plot <- function(R, n, gen_fun, true_mean, title, filename, ...) {
  set.seed(1234L)
  means <- numeric(R)
  ICs   <- matrix(NA_real_, R, 2, dimnames = list(NULL, c("LI","LS")))
  for (r in 1:R) {
    x <- gen_fun(n, ...)
    means[r] <- mean(x)
    ICs[r,]  <- ic95_t_onerep(x)
  }
  cover <- (ICs[,1] <= true_mean & true_mean <= ICs[,2])
  cov_rate <- mean(cover)
  df <- tibble(replica = 1:R, media = means, LI = ICs[,1], LS = ICs[,2], cubre = cover)

  g <- ggplot(df, aes(y = replica)) +
    geom_segment(aes(x = LI, xend = LS, yend = replica, color = cubre), linewidth = 1.1) +
    geom_point(aes(x = media), size = 1.7) +
    geom_vline(xintercept = true_mean, linetype = "dashed") +
    scale_color_manual(values = c("TRUE" = "forestgreen","FALSE" = "red3")) +
    labs(title = paste0("IC (95%) por réplica – ", title),
         x = "Media por réplica (minutos)", y = "Réplicas",
         subtitle = sprintf("Cobertura observada ≈ %.1f%%", 100*cov_rate)) +
    theme_minimal(base_size = 12)
  ggsave(file.path(out_dir, filename), g, width = 8.5, height = 6)
  g
}

5 Resultados

5.1 Simulación y medias por réplica

# Normal(mu=15, sd=5)
medias_norm <- replicate_means(R, n, rnorm, mean = mu_n, sd = sd_n)
# Exponencial(media=3.5) -> rate = 1/3.5 (forzamos stats::rexp para evitar conflictos)
medias_exp  <- replicate_means(R, n, stats::rexp,  rate = rate_e)

# Reparación defensiva en caso (raro) de NA
if (anyNA(medias_exp)) {
  warning("Se detectaron NA en medias_exp; re-simulando esas réplicas puntuales.")
  idx <- which(is.na(medias_exp))
  for (j in idx) medias_exp[j] <- mean(stats::rexp(n, rate = rate_e))
}

# Validaciones
stopifnot(length(medias_norm) == R, length(medias_exp) == R)
stopifnot(!anyNA(medias_norm), !anyNA(medias_exp))

tabla_medias <- tibble(
  replica = 1:R,
  media_normal_min      = medias_norm,
  media_exponencial_min = medias_exp
)
knitr::kable(head(tabla_medias, 10), digits = 4,
             caption = "Primeras 10 de las 30 medias por réplica (minutos).")
Primeras 10 de las 30 medias por réplica (minutos).
replica media_normal_min media_exponencial_min
1 -0.2507 2.8079
2 -0.5771 3.0537
3 -0.4443 3.2202
4 0.2871 3.0322
5 0.2011 3.7062
6 -0.1131 4.9138
7 -0.1017 3.2757
8 0.2357 2.5248
9 0.2187 2.6494
10 -0.0334 2.9433
write.csv(tabla_medias, file.path(out_dir, "tabla_medias_30_replicas.csv"), row.names = FALSE)

5.2 IC 95% para la media poblacional (t sobre las 30 medias)

ic_norm <- ic95_t(medias_norm)
ic_exp  <- ic95_t(medias_exp)

resumen <- tibble(
  distribucion      = c("Normal(15,5)","Exponencial(media=3.5)"),
  n_por_replica     = n,
  replicas          = R,
  media_de_las_medias = c(mean(medias_norm), mean(medias_exp)),
  sd_de_las_medias    = c(sd(medias_norm),  sd(medias_exp)),
  IC95_LI           = c(ic_norm["LI"], ic_exp["LI"]),
  IC95_LS           = c(ic_norm["LS"], ic_exp["LS"])
)

knitr::kable(resumen, digits = 4, caption = "IC 95% de la media poblacional (aplicado a las 30 **medias**).")
IC 95% de la media poblacional (aplicado a las 30 medias).
distribucion n_por_replica replicas media_de_las_medias sd_de_las_medias IC95_LI IC95_LS
Normal(15,5) 20 30 -0.0213 0.2346 -0.1089 0.0663
Exponencial(media=3.5) 20 30 3.4837 0.6542 3.2394 3.7280
write.csv(resumen, file.path(out_dir, "resumen_IC95.csv"), row.names = FALSE)

5.3 Gráficos de las medias por réplica (minutos)

plot_hist <- function(v, titulo) {
  ggplot(tibble(x = v), aes(x)) +
    geom_histogram(bins = 8, linewidth = 0.2) +
    labs(title = titulo, x = "Media por réplica (minutos)", y = "Frecuencia") +
    theme_minimal(base_size = 12)
}
plot_qq <- function(v, titulo) {
  ggplot(tibble(sample = v), aes(sample = sample)) +
    stat_qq() + stat_qq_line() +
    labs(title = titulo, x = "Cuantiles teóricos N(0,1)", y = "Cuantiles de la muestra") +
    theme_minimal(base_size = 12)
}
plot_box <- function(v, titulo) {
  ggplot(tibble(x = "Medias", y = v), aes(x, y)) +
    geom_boxplot(outlier.alpha = 0.6) +
    labs(title = titulo, x = "", y = "Media por réplica (minutos)") +
    theme_minimal(base_size = 12)
}

g1 <- plot_hist(medias_norm, "Histograma – Medias (30 réplicas) – Normal(15,5)")
g2 <- plot_qq(medias_norm,   "QQ-plot – Medias – Normal(15,5)")
g3 <- plot_box(medias_norm,  "Caja – Medias – Normal(15,5)")

g4 <- plot_hist(medias_exp,  "Histograma – Medias (30 réplicas) – Exponencial(media=3.5)")
g5 <- plot_qq(medias_exp,    "QQ-plot – Medias – Exponencial(media=3.5)")
g6 <- plot_box(medias_exp,   "Caja – Medias – Exponencial(media=3.5)")

g1; g2; g3; g4; g5; g6

ggsave(file.path(out_dir,"hist_medias_normal.png"), g1, width=7.5, height=5.2)
ggsave(file.path(out_dir,"qq_medias_normal.png"),   g2, width=7.5, height=5.2)
ggsave(file.path(out_dir,"box_medias_normal.png"),  g3, width=5.5, height=5.2)
ggsave(file.path(out_dir,"hist_medias_exp.png"),    g4, width=7.5, height=5.2)
ggsave(file.path(out_dir,"qq_medias_exp.png"),      g5, width=7.5, height=5.2)
ggsave(file.path(out_dir,"box_medias_exp.png"),     g6, width=5.5, height=5.2)

5.4 Cobertura de IC por réplica (visual didáctica)

cov_norm <- coverage_plot(R, n, rnorm, true_mean = mu_n,
                          title = "Normal(15,5)", filename = "ICs_por_replica_Normal.png",
                          mean = mu_n, sd = sd_n)
cov_exp  <- coverage_plot(R, n, stats::rexp,  true_mean = mean_e,
                          title = "Exponencial(media=3.5)", filename = "ICs_por_replica_Exp.png",
                          rate = rate_e)
cov_norm; cov_exp

6 Análisis y discusión

Fórmula del IC (95%) para \(\mu\) con \(\sigma\) desconocida, t-Student sobre las 30 medias:
\[ \left[\ \bar M - t_{0.975,\ R-1}\frac{s_M}{\sqrt{R}},\ \ \bar M + t_{0.975,\ R-1}\frac{s_M}{\sqrt{R}}\ \right], \] donde \(\bar M\) y \(s_M\) son la media y la desviación estándar del conjunto de 30 medias por réplica \((M_1,\dots,M_{30})\).

Interpretación de “95%”: Si repitiésemos este procedimiento muchas veces, aproximadamente 95% de los IC construidos así contendrían a la media poblacional verdadera. Suposiciones: independencia de réplicas, tamaño \(n\) moderado, y normalidad aproximada de las medias por el Teorema Central del Límite (TCL).

Comparación Normal vs. Exponencial: Los datos crudos exponenciales son asimétricos a la derecha, pero sus medias por réplica (con \(n=20\)) muestran comportamiento cercano a Normal (TCL). En Normal, la aproximación es aún más clara. Las amplitudes de IC se relacionan con la variabilidad de las medias (\(\text{SD}=\sigma/\sqrt{n}\)).

Sensibilidad: Aumentar \(n\) reduce la variabilidad de cada media por réplica y estrecha los IC; aumentar \(R\) reduce la SE de \(\bar M\) y también estrecha los IC. En ambos casos, la aproximación normal mejora.

7 Ajuste/validación de la distribución de las medias por réplica (Stat:Fit emulado en R)

# Pruebas de normalidad (Shapiro-Wilk) sobre las MEDIAS
sw_norm <- shapiro.test(medias_norm)
sw_exp  <- shapiro.test(medias_exp)
norm_test <- tibble(
  conjunto = c("Medias Normal(15,5)","Medias Exponencial(media=3.5)"),
  W        = c(unname(sw_norm$statistic), unname(sw_exp$statistic)),
  p_value  = c(sw_norm$p.value, sw_exp$p.value)
)
knitr::kable(norm_test, digits = 4, caption = "Prueba de normalidad (Shapiro-Wilk) sobre las 30 MEDIAS.")
Prueba de normalidad (Shapiro-Wilk) sobre las 30 MEDIAS.
conjunto W p_value
Medias Normal(15,5) 0.9316 0.0543
Medias Exponencial(media=3.5) 0.9365 0.0731
# Ajustes comparativos para las MEDIAS del escenario Exponencial
suppressWarnings({
  fit_norm_e <- fitdistrplus::fitdist(medias_exp,  "norm")
  fit_logn_e <- fitdistrplus::fitdist(medias_exp,  "lnorm")
  fit_gamm_e <- fitdistrplus::fitdist(medias_exp,  "gamma")
})
ajustes_exp <- tibble(
  modelo = c("Normal","Lognormal","Gamma"),
  AIC    = c(fit_norm_e$aic, fit_logn_e$aic, fit_gamm_e$aic)
) %>% arrange(AIC)
knitr::kable(ajustes_exp, digits = 2, caption = "AIC de modelos candidatos para las MEDIAS (escenario Exponencial).")
AIC de modelos candidatos para las MEDIAS (escenario Exponencial).
modelo AIC
Lognormal 60.08
Gamma 60.71
Normal 62.65

Conclusión del ajuste: En ambos escenarios, la Normal resulta una descripción razonable de las medias por réplica (consistente con el TCL). Si algún modelo alternativo muestra AIC menor por margen pequeño, se prefiere la Normal por soporte teórico, parsimonia e interpretación del IC clásico.

8 Conclusiones

  1. Los IC del 95% para la media poblacional construidos con t-Student sobre las medias por réplica son apropiados con \(R=30\) y \(n=20\).
  2. La aproximación a Normal de las medias por réplica es clara, incluso cuando los datos crudos provienen de una distribución asimétrica (Exponencial).
  3. Aumentar \(n\) y/o \(R\) mejora la precisión de los IC (menor amplitud) y refuerza la validez del enfoque.
  4. El marco es reproducible (semilla fija, código documentado) y exporta tablas/figuras para entrega formal.

9 Referencias

10 Apéndices

10.1 A. Código íntegro (reunido)

El código aparece a lo largo del documento; se duplica aquí para fácil copia/pega si el docente lo exige.

# Paquetes
# -- Fijar espejo CRAN para evitar el error "trying to use CRAN without setting a mirror"
if (is.null(getOption("repos")) || getOption("repos")["CRAN"] %in% c(NULL, "@CRAN@", "")) {
  options(repos = c(CRAN = "https://cloud.r-project.org"))
}
req_pkgs <- c("ggplot2","dplyr","tibble","knitr","fitdistrplus")
to_install <- setdiff(req_pkgs, rownames(installed.packages()))
if (length(to_install) > 0) {
  try(install.packages(to_install, quiet = TRUE), silent = TRUE)
}
invisible(lapply(req_pkgs, function(p){
  if (!suppressWarnings(require(p, character.only = TRUE))) {
    stop(sprintf("No se pudo cargar el paquete '%s'. Instálalo manualmente: install.packages('%s')", p, p))
  }
}))

# Parámetros
set.seed(1234L); n <- 20L; R <- 30L; mu_n <- 15; sd_n <- 5; mean_e <- 3.5; rate_e <- 1/mean_e
out_dir <- "output"; if (!dir.exists(out_dir)) dir.create(out_dir, recursive = TRUE)

ic95_t <- function(v){ v<-v[!is.na(v)]; m<-mean(v); s<-sd(v); N<-length(v); se<-s/sqrt(N); tcrit<-qt(0.975, df=N-1); c(LI=m-tcrit*se, LS=m+tcrit*se) }
ic95_t_onerep <- function(x, alpha=0.05){ x<-x[!is.na(x)]; n<-length(x); m<-mean(x); s<-sd(x); se<-s/sqrt(n); tcrit<-qt(1-alpha/2, df=n-1); c(LI=m-tcrit*se, LS=m+tcrit*se) }
replicate_means <- function(R,n,gen_fun,...) replicate(R, mean(gen_fun(n, ...)))

coverage_plot <- function(R, n, gen_fun, true_mean, title, filename, ...) {
  set.seed(1234L)
  means <- numeric(R); ICs <- matrix(NA_real_, R, 2, dimnames=list(NULL, c("LI","LS")))
  for (r in 1:R) { x <- gen_fun(n, ...); means[r] <- mean(x); ICs[r,] <- ic95_t_onerep(x) }
  cover <- (ICs[,1] <= true_mean & true_mean <= ICs[,2]); cov_rate <- mean(cover)
  df <- tibble(replica=1:R, media=means, LI=ICs[,1], LS=ICs[,2], cubre=cover)
  g <- ggplot(df, aes(y=replica)) + geom_segment(aes(x=LI,xend=LS,yend=replica,color=cubre),linewidth=1.1) +
    geom_point(aes(x=media), size=1.7) + geom_vline(xintercept=true_mean, linetype="dashed") +
    scale_color_manual(values=c("TRUE"="forestgreen","FALSE"="red3")) +
    labs(title=paste0("IC (95%) por réplica – ", title),
         x="Media por réplica (minutos)", y="Réplicas",
         subtitle=sprintf("Cobertura observada ≈ %.1f%%", 100*cov_rate)) + theme_minimal(base_size=12)
  ggsave(file.path(out_dir, filename), g, width=8.5, height=6); g
}

# Simulación
medias_norm <- replicate_means(R,n,rnorm, mean=mu_n, sd=sd_n)
medias_exp  <- replicate_means(R,n,stats::rexp,  rate=rate_e)
# Reparación defensiva si hubiera NA (caso raro)
if (anyNA(medias_exp)) {
  idx <- which(is.na(medias_exp))
  for (j in idx) medias_exp[j] <- mean(stats::rexp(n, rate = rate_e))
}
stopifnot(length(medias_norm)==R, length(medias_exp)==R, !anyNA(medias_norm), !anyNA(medias_exp))

tabla_medias <- tibble(replica=1:R, media_normal_min=medias_norm, media_exponencial_min=medias_exp)
write.csv(tabla_medias, file.path(out_dir,"tabla_medias_30_replicas.csv"), row.names=FALSE)

# IC sobre las 30 medias
ic_norm <- ic95_t(medias_norm); ic_exp <- ic95_t(medias_exp)
resumen <- tibble(distribucion=c("Normal(15,5)","Exponencial(media=3.5)"),
                  n_por_replica=n, replicas=R,
                  media_de_las_medias=c(mean(medias_norm), mean(medias_exp)),
                  sd_de_las_medias=c(sd(medias_norm), sd(medias_exp)),
                  IC95_LI=c(ic_norm["LI"], ic_exp["LI"]), IC95_LS=c(ic_norm["LS"], ic_exp["LS"]))
write.csv(resumen, file.path(out_dir, "resumen_IC95.csv"), row.names=FALSE)

10.2 B. Semillas y tablas completas

  • Semilla usada: set.seed(1234) (global).
  • Archivos exportados automáticamente a output/:
    • tabla_medias_30_replicas.csv (30 medias por réplica en ambos escenarios).
    • resumen_IC95.csv (tabla consolidada de IC).
    • PNG de gráficos y cobertura por réplica.

10.3 C. sessionInfo()

sessionInfo()
## R version 4.5.1 (2025-06-13 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 10 x64 (build 19045)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=Spanish_Colombia.utf8  LC_CTYPE=Spanish_Colombia.utf8   
## [3] LC_MONETARY=Spanish_Colombia.utf8 LC_NUMERIC=C                     
## [5] LC_TIME=Spanish_Colombia.utf8    
## 
## time zone: America/Bogota
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] fitdistrplus_1.2-4 survival_3.8-3     MASS_7.3-65        knitr_1.50        
## [5] tibble_3.3.0       dplyr_1.1.4        ggplot2_4.0.0     
## 
## loaded via a namespace (and not attached):
##  [1] Matrix_1.7-3       gtable_0.3.6       jsonlite_2.0.0     compiler_4.5.1    
##  [5] tidyselect_1.2.1   jquerylib_0.1.4    splines_4.5.1      scales_1.4.0      
##  [9] yaml_2.3.10        fastmap_1.2.0      lattice_0.22-7     R6_2.6.1          
## [13] labeling_0.4.3     generics_0.1.4     bslib_0.9.0        pillar_1.11.1     
## [17] RColorBrewer_1.1-3 rlang_1.1.6        cachem_1.1.0       xfun_0.53         
## [21] sass_0.4.10        S7_0.2.0           cli_3.6.5          withr_3.0.2       
## [25] magrittr_2.0.3     digest_0.6.37      grid_4.5.1         rstudioapi_0.17.1 
## [29] lifecycle_1.0.4    vctrs_0.6.5        evaluate_1.0.5     glue_1.8.0        
## [33] farver_2.1.2       rmarkdown_2.29     tools_4.5.1        pkgconfig_2.0.3   
## [37] htmltools_0.5.8.1