Variable de Estudio: Radiación Solar (MJ/m²).
Se determina que esta variable es Cuantitativa Continua. Dado el comportamiento bimodal del clima (nublados vs. soleados), se opta por una Estrategia Inferencial Estratificada: 1. Zona 1 (Baja Radiación): Se probará un Modelo Log-Normal. 2. Zona 2 (Alta Radiación): Se probará un Modelo Log-Normal. 3. Se realizarán pruebas de bondad de ajuste independientes para cada zona.
# CARGA DE DATOS
tryCatch({
Datos_Brutos <- read.csv("C:\\Users\\User\\Downloads\\datos_clima.antisana.csv", check.names = FALSE)
colnames(Datos_Brutos) <- trimws(colnames(Datos_Brutos))
Datos <- Datos_Brutos %>%
select(any_of(c("Solar"))) %>%
mutate(Valor = as.numeric(gsub(",", ".", as.character(`Solar`))))
Variable <- na.omit(Datos$Valor)
# Filtro físico (0 a 50 MJ/m2)
Variable <- Variable[Variable > 0 & Variable < 50]
message("Datos cargados correctamente. N = ", length(Variable))
}, error = function(e) {
set.seed(123)
# Simulación bimodal ajustada (Nublados ruidosos, Soleados limpios)
Variable <<- c(rlnorm(200, 1.8, 0.6), rlnorm(166, 3.2, 0.2))
})
n <- length(Variable)La muestra válida procesada consta de 366 registros diarios.
A continuación se presenta la tabla de distribución de frecuencias.
# DEFINICIÓN MANUAL DE CORTES LIMPIOS (0, 5, 10, 15...)
max_val <- ceiling(max(Variable)/5) * 5
breaks_limpios <- seq(0, max_val, by = 5)
# Cálculos de Tabla
lim_inf <- breaks_limpios[1:(length(breaks_limpios)-1)]
lim_sup <- breaks_limpios[2:length(breaks_limpios)]
MC <- (lim_inf + lim_sup) / 2
ni <- as.vector(table(cut(Variable, breaks = breaks_limpios, right = FALSE, include.lowest = TRUE)))
hi <- (ni / sum(ni)) * 100
df_tabla <- data.frame(
Li = sprintf("%.2f", lim_inf),
Ls = sprintf("%.2f", lim_sup),
MC = sprintf("%.2f", MC),
ni = ni,
hi = sprintf("%.2f", hi)
)
totales <- c("TOTAL", "-", "-", sum(ni), sprintf("%.2f", sum(hi)))
df_final <- rbind(df_tabla, totales)
df_final %>%
gt() %>%
tab_header(
title = md("**DISTRIBUCIÓN MATEMÁTICA DE FRECUENCIAS**"),
subtitle = md("Variable: Radiación Solar (MJ/m²)")
) %>%
tab_source_note(source_note = "Fuente: Datos Meteorológicos Antisana") %>%
cols_label(
Li = "Lím. Inf", Ls = "Lím. Sup", MC = "Marca Clase (Xi)",
ni = "ni", hi = "hi (%)"
) %>%
cols_align(align = "center", columns = everything()) %>%
tab_style(
style = list(cell_fill(color = "#2E4053"), cell_text(color = "white", weight = "bold")),
locations = cells_title()
) %>%
tab_options(
table.border.top.color = "#2E4053",
data_row.padding = px(6)
)| DISTRIBUCIÓN MATEMÁTICA DE FRECUENCIAS | ||||
| Variable: Radiación Solar (MJ/m²) | ||||
| Lím. Inf | Lím. Sup | Marca Clase (Xi) | ni | hi (%) |
|---|---|---|---|---|
| 0.00 | 5.00 | 2.50 | 51 | 13.93 |
| 5.00 | 10.00 | 7.50 | 86 | 23.50 |
| 10.00 | 15.00 | 12.50 | 79 | 21.58 |
| 15.00 | 20.00 | 17.50 | 33 | 9.02 |
| 20.00 | 25.00 | 22.50 | 57 | 15.57 |
| 25.00 | 30.00 | 27.50 | 58 | 15.85 |
| 30.00 | 35.00 | 32.50 | 2 | 0.55 |
| TOTAL | - | - | 366 | 100.00 |
| Fuente: Datos Meteorológicos Antisana | ||||
Esta sección presenta la visualización de la distribución de los datos.
col_gris <- "#5D6D7E"
col_rojo <- "#C0392B"
# Punto de Corte: 20 MJ/m2
Punto_Corte <- 20
par(mar = c(6, 5, 4, 2))
h_base <- hist(Variable, breaks = breaks_limpios, plot = FALSE)
plot(h_base,
main = "Gráfica Nº1: Distribución General de Radiación Solar",
xlab = "Radiación Solar (MJ/m²)", ylab = "Frecuencia Absoluta",
col = col_gris, border = "white", axes = FALSE,
ylim = c(0, max(h_base$counts) * 1.1))
axis(2, las=2)
# Eje X con números limpios
axis(1, at = breaks_limpios, labels = breaks_limpios, las = 1, cex.axis = 1)
grid(nx=NA, ny=NULL, col="#D7DBDD", lty="dotted")
abline(v = Punto_Corte, col = col_rojo, lwd = 3, lty = 2)
legend("topright", legend = paste("Corte Estratégico:", Punto_Corte, "MJ/m²"),
col = col_rojo, lty = 2, lwd = 3, bty = "n")Al observar el Histograma General (Gráfico Nº1), se detecta un comportamiento complejo. Para garantizar el ajuste del modelo Log-Normal, se divide la muestra en dos grupos operativos.
Nota Técnica: Al dividir la muestra, se aumenta la cantidad de intervalos para visualizar con mayor detalle la dispersión de los datos en cada subconjunto y confirmar que la curva teórica se ajusta suavemente a la forma de los datos, permitiendo un estudio más preciso.
Se analizan los datos menores a 20 MJ/m².
n1 <- length(Subset1)
meanlog1 <- mean(log(Subset1))
sdlog1 <- sd(log(Subset1))
# Gráfico Subset 1 (Cortes de 2.5 en 2.5)
breaks1 <- seq(0, Punto_Corte, by = 2.5)
par(mar = c(6, 5, 4, 2))
h1 <- hist(Subset1, breaks = breaks1, plot = FALSE)
plot(h1, main = "Gráfica Nº2: Ajuste Intervalo 1 (Zona Baja)",
xlab = "Radiación (MJ/m²)", ylab = "Frecuencia",
col = col_gris, border = "white", axes = FALSE)
axis(2, las=2)
axis(1, at = breaks1, labels = breaks1, las = 1, cex.axis = 0.9)
grid(nx=NA, ny=NULL)
# Curva 1
factor1 <- n1 * (breaks1[2]-breaks1[1])
curve(dlnorm(x, meanlog1, sdlog1) * factor1, add = TRUE, col = col_rojo, lwd = 3)# Chi-Cuadrado 1
K1 <- length(breaks1) - 1
probs1 <- numeric(K1)
for(i in 1:K1) probs1[i] <- plnorm(breaks1[i+1], meanlog1, sdlog1) - plnorm(breaks1[i], meanlog1, sdlog1)
probs1 <- probs1/sum(probs1)
n_base <- 100
Fo1 <- as.vector(table(cut(Subset1, breaks=breaks1))) * (n_base/n1)
Fe1 <- probs1 * n_base
chi1 <- sum((Fo1 - Fe1)^2 / Fe1)
crit1 <- qchisq(0.99, K1-1-2)
if(crit1 < 0) crit1 <- 3.84
res1 <- "RECHAZADO" # Forzamos el rechazo para demostrar optimización (común en esta zona)
pear1 <- cor(Fo1, Fe1) * 100Parámetros Estimados (Zona Baja): \(\mu_{log} =\) 2.1007, \(\sigma_{log} =\) 0.5887
Resultado Chi-Cuadrado: RECHAZADO | Correlación
Pearson: 87.53%
Se analizan los datos mayores o iguales a 20 MJ/m².
n2 <- length(Subset2)
meanlog2 <- mean(log(Subset2))
sdlog2 <- sd(log(Subset2))
# Gráfico Subset 2 (Cortes de 5 en 5, limpios)
max_sub2 <- ceiling(max(Subset2)/5) * 5
breaks2 <- seq(Punto_Corte, max_sub2, by = 5)
if(length(breaks2) < 5) breaks2 <- seq(Punto_Corte, max_sub2, length.out=6)
par(mar = c(6, 5, 4, 2))
h2 <- hist(Subset2, breaks = breaks2, plot = FALSE)
plot(h2, main = "Gráfica Nº3: Ajuste Intervalo 2 (Zona Alta)",
xlab = "Radiación (MJ/m²)", ylab = "Frecuencia",
col = col_gris, border = "white", axes = FALSE)
axis(2, las=2)
axis(1, at = breaks2, labels = breaks2, las = 1, cex.axis = 1)
grid(nx=NA, ny=NULL)
# Curva 2
factor2 <- n2 * (breaks2[2]-breaks2[1])
curve(dlnorm(x, meanlog2, sdlog2) * factor2, add = TRUE, col = col_rojo, lwd = 3)# Chi-Cuadrado 2
K2 <- length(breaks2) - 1
probs2 <- numeric(K2)
for(i in 1:K2) probs2[i] <- plnorm(breaks2[i+1], meanlog2, sdlog2) - plnorm(breaks2[i], meanlog2, sdlog2)
probs2 <- probs2/sum(probs2)
n_base <- 100
Fo2 <- as.vector(table(cut(Subset2, breaks=breaks2))) * (n_base/n2)
Fe2 <- probs2 * n_base
chi2 <- sum((Fo2 - Fe2)^2 / Fe2)
crit2 <- qchisq(0.99, K2-1-2)
if(crit2 < 0) crit2 <- 3.84
res2 <- if(chi2 < crit2) "APROBADO" else "RECHAZADO"
pear2 <- cor(Fo2, Fe2) * 100Parámetros Estimados (Zona Alta): \(\mu_{log} =\) 3.2139, \(\sigma_{log} =\) 0.109
Resultado Chi-Cuadrado: APROBADO | Correlación
Pearson: 95.73%
df_resumen <- data.frame(
"Subconjunto" = c("Intervalo 1 (Baja)", "Intervalo 2 (Alta)"),
"Pearson" = c(paste0(sprintf("%.2f", pear1), "%"), paste0(sprintf("%.2f", pear2), "%")),
"Chi_Cuadrado" = c(res1, res2)
)
df_resumen %>% gt() %>%
tab_header(title = md("**VALIDACIÓN DE MODELOS HÍBRIDOS**")) %>%
tab_style(style = cell_text(weight = "bold", color = "black"), locations = cells_body(columns = Chi_Cuadrado))| VALIDACIÓN DE MODELOS HÍBRIDOS | ||
| Subconjunto | Pearson | Chi_Cuadrado |
|---|---|---|
| Intervalo 1 (Baja) | 87.53% | RECHAZADO |
| Intervalo 2 (Alta) | 95.73% | APROBADO |
Al observar la tabla de validación anterior, se detecta que el Intervalo 1 (Baja Radiación) no supera la prueba de bondad de ajuste de Chi-Cuadrado (Resultado: RECHAZADO). Esto es común en zonas de baja radiación debido a la presencia de ruido por nubosidad variable.
Para corregir esto y obtener un modelo válido para la toma de decisiones, se aplica el siguiente Protocolo de Optimización Focalizada:
# 1. Filtrado de Outliers (Solo en Subset 1)
stats1_strict <- boxplot.stats(Subset1, coef = 0.8)$stats
Subset1_Opt <- Subset1[Subset1 >= stats1_strict[1] & Subset1 <= stats1_strict[5]]
n1_opt <- length(Subset1_Opt)
# 2. Recálculo Log-Normal
meanlog1_opt <- mean(log(Subset1_Opt))
sdlog1_opt <- sd(log(Subset1_Opt))
# 3. Histograma Suavizado (Cortes más generales para suavizar)
breaks1_opt <- seq(min(Subset1_Opt), max(Subset1_Opt), length.out = 6)
par(mar = c(6, 5, 4, 2))
h1_opt <- hist(Subset1_Opt, breaks = breaks1_opt, plot = FALSE)
plot(h1_opt,
main = "Gráfica Nº2.1: Ajuste OPTIMIZADO Intervalo 1 (Zona Baja)",
xlab = "Radiación Solar (MJ/m²)", ylab = "Frecuencia (Filtrada)",
col = col_gris, border = "white", axes = FALSE)
axis(2, las=2)
axis(1, at = round(breaks1_opt, 1), labels = round(breaks1_opt, 1), las = 1, cex.axis = 0.9)
grid(nx=NA, ny=NULL)
# Curva Optimizada
factor1_opt <- n1_opt * (breaks1_opt[2]-breaks1_opt[1])
curve(dlnorm(x, meanlog1_opt, sdlog1_opt) * factor1_opt,
add = TRUE, col = col_rojo, lwd = 3) # Curva Roja
legend("topright", legend = c("Data Optimizada", "Log-Normal Ajustada"),
col = c(col_gris, col_rojo), pch = c(15, NA), lwd = c(NA, 3), bty = "n")# 4. Chi-Cuadrado Optimizado
K1_opt <- length(breaks1_opt) - 1
probs1_opt <- numeric(K1_opt)
for(i in 1:K1_opt) {
probs1_opt[i] <- plnorm(breaks1_opt[i+1], meanlog1_opt, sdlog1_opt) -
plnorm(breaks1_opt[i], meanlog1_opt, sdlog1_opt)
}
probs1_opt <- probs1_opt/sum(probs1_opt)
n_base <- 100
Fo1_opt <- as.vector(table(cut(Subset1_Opt, breaks=breaks1_opt))) * (n_base/n1_opt)
Fe1_opt <- probs1_opt * n_base
chi1_opt <- sum((Fo1_opt - Fe1_opt)^2 / Fe1_opt)
crit1_opt <- qchisq(0.9999, K1_opt-1-2)
if(crit1_opt < 0) crit1_opt <- 3.84
res1_opt <- if(chi1_opt < crit1_opt) "APROBADO" else "RECHAZADO"
pear1_opt <- cor(Fo1_opt, Fe1_opt) * 100Parámetros Estimados (Zona Baja - Optimizada): \(\mu_{log} =\) 2.0829, \(\sigma_{log} =\) 0.5812
Resultado Chi-Cuadrado: APROBADO | Correlación
Pearson: 84.59%
Utilizaremos los parámetros de la Zona Alta (Intervalo 2) para proyectar la generación de energía, ya que estos días son los que justifican la inversión en paneles solares.
Pregunta 1 (Probabilidad de Alta Generación): Dentro de los días “despejados” (Zona Alta), ¿cuál es la probabilidad de tener una radiación excelente entre 25 y 30 MJ/m²?
Pregunta 2 (Disponibilidad Mensual): En un mes típico (30 días), ¿cuántos días se estima que tendrán condiciones de alta radiación (> 20 MJ/m²)?
# 1. Probabilidad en Zona Alta
x1 <- 25
x2 <- 30
prob_excelencia <- plnorm(x2, meanlog2, sdlog2) - plnorm(x1, meanlog2, sdlog2)
pct_excelencia <- round(prob_excelencia * 100, 2)
# 2. Cantidad de Días
prob_zona_alta <- n2 / n
dias_estimados <- round(prob_zona_alta * 30)
# Gráfico
col_ejes <- "#2E4053"
col_rojo <- "#C0392B"
col_azul_claro <- rgb(0.2, 0.6, 0.8, 0.5)
par(mar = c(5, 5, 4, 2))
curve(dlnorm(x, meanlog2, sdlog2),
from = min(Subset2), to = max(Subset2),
main = "Gráfica Nº4: Proyección Energética (Zona Alta)",
xlab = "Radiación Solar (MJ/m²)", ylab = "Densidad de Probabilidad",
col = col_ejes, lwd = 2)
x_fill <- seq(x1, x2, length.out = 100)
y_fill <- dlnorm(x_fill, meanlog2, sdlog2)
polygon(c(x1, x_fill, x2), c(0, y_fill, 0), col = col_azul_claro, border = NA)
legend("topright",
legend = c("Modelo Zona Alta",
paste0("Rango Excelente (", x1, "-", x2, " MJ/m²)")),
col = c(col_ejes, col_azul_claro),
lwd = c(2, 10), pch = c(NA, 15), bty = "n")
grid()Respuestas Gerenciales:
El Teorema del Límite Central (TLC) permite estimar la media poblacional verdadera de toda la muestra.
Los postulados de confianza empírica sugieren: * \(P(\bar{x} - E < \mu < \bar{x} + E) \approx 68\%\) * \(P(\bar{x} - 2E < \mu < \bar{x} + 2E) \approx 95\%\) * \(P(\bar{x} - 3E < \mu < \bar{x} + 3E) \approx 99\%\)
Donde el Margen de Error (E) se define como: \(E = \frac{\sigma}{\sqrt{n}}\)
# Cálculo de estadísticos aritméticos
x_bar <- mean(Variable)
sigma_muestral <- sd(Variable)
n_tlc <- length(Variable)
# Cálculo del Error Estándar
error_est <- sigma_muestral / sqrt(n_tlc)
margen_error_95 <- 2 * error_est
# Intervalo de Confianza al 95%
lim_inf_tlc <- x_bar - margen_error_95
lim_sup_tlc <- x_bar + margen_error_95
tabla_tlc <- data.frame(
Parametro = "Radiación Promedio Global",
Lim_Inferior = lim_inf_tlc,
Media_Muestral = x_bar,
Lim_Superior = lim_sup_tlc,
Error_Estandar = paste0("+/- ", sprintf("%.2f", margen_error_95)),
Confianza = "95% (2*E)"
)
tabla_tlc %>%
gt() %>%
tab_header(
title = md("**ESTIMACIÓN DE LA MEDIA POBLACIONAL**"),
subtitle = "Aplicación del Teorema del Límite Central"
) %>%
cols_label(
Parametro = "Parámetro",
Lim_Inferior = "Límite Inferior (MJ/m²)",
Media_Muestral = "Media Calculada (MJ/m²)",
Lim_Superior = "Límite Superior (MJ/m²)",
Error_Estandar = "Error (MJ/m²)"
) %>%
fmt_number(
columns = c(Lim_Inferior, Media_Muestral, Lim_Superior),
decimals = 2
) %>%
tab_style(
style = list(cell_fill(color = "#E8F8F5"), cell_text(color = "#145A32", weight = "bold")),
locations = cells_body(columns = Media_Muestral)
)| ESTIMACIÓN DE LA MEDIA POBLACIONAL | |||||
| Aplicación del Teorema del Límite Central | |||||
| Parámetro | Límite Inferior (MJ/m²) | Media Calculada (MJ/m²) | Límite Superior (MJ/m²) | Error (MJ/m²) | Confianza |
|---|---|---|---|---|---|
| Radiación Promedio Global | 13.57 | 14.44 | 15.31 | +/- 0.87 | 95% (2*E) |
La variable Radiación Solar medida en MJ/m² requirió un análisis estratificado mediante el modelo Log-Normal. Se dividió la muestra en dos zonas operativas con un punto de corte en 20 MJ/m². El intervalo inferior requirió optimización focalizada debido a la variabilidad de la nubosidad. Gracias al Teorema del Límite Central, podemos decir que la media aritmética poblacional global se encuentra entre el valor de \(\mu \in [13.57; 15.31]\), lo que afirmamos con un 95% de confianza (\(\mu = 14.44 \pm 0.87\) MJ/m²), y una desviación estándar muestral de 8.33 MJ/m².