UNIVERSIDAD CENTRAL DEL ECUADOR- FIGEMPA, INGENIERÍA AMBIENTAL

#Estadística Inferencial 
#17/01/2026
#Lorien Arcentales
# Carga de paquetes

library(gt)
library(dplyr)
#1. CARGA DE DATOS
datos<-read.csv("city_day.csv", header = TRUE, dec = ".",
                sep = ",")
#Extraccion de la variabela OZONO y los "-" de la variable porque son valores inexistentes, 
# para un mejor analisis, cambia tamaño muestral de 29531 a 25509
ozono <- datos$O3[datos$O3 != "-"]
length(ozono)
## [1] 25509
ozono <- as.numeric(ozono)
#Justificación porque la variable es continua: porque puede tomar cualquier valor dentro de los números reales positivos, incluido el cero, sin presentar saltos en su dominio o la variable cambia de manera gradual y no pasa bruscamente de un valor a otro.

# 2. TDF simplificada
Histograma_ozono<-hist(ozono,plot = FALSE)
#Elemnetos simplificados 
breaks <- Histograma_ozono$breaks
Li <- breaks[1:(length(breaks)-1)]
Ls <- breaks[2:length(breaks)]
ni<-Histograma_ozono$counts
N<-length(ozono)
hi<- (ni / N) * 100
TDF_ozonosimplificado <- data.frame(
  Intervalo = paste0("[", round(Li,2), " - ", round(Ls,2), ")"),
  ni = ni,
  hi= round(hi, 2))
colnames(TDF_ozonosimplificado) <- c(
  "Intervalo",
  "ni",
  "hi(%)"
)
totales<- data.frame(
  Intervalo = "Totales",
  ni = sum(ni),           # suma total de ni
  hi = sum(hi)
)
colnames(totales) <- c(
  "Intervalo",
  "ni",
  "hi(%)"
)
# Agregar al final de la tabla
TDF_ozonosimplificado <- rbind(TDF_ozonosimplificado, totales)
TDF_ozonosimplificado %>%
  gt() %>%
  tab_header(
    title = md("*Tabla Nro. 1*"),
    subtitle = md("**Distribucion de frecuencia simplificado de concentración de ozono,estudio calidad del aire en India entre 2015-2020 **")
  ) %>%
  tab_source_note(
    source_note = md("Autor: Grupo 2\n Fuente:https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india")
  ) %>%
  tab_options(
    table.border.top.color = "black",
    table.border.bottom.color = "black",
    table.border.top.style = "solid",
    table.border.bottom.style = "solid",
    column_labels.border.top.color = "black",
    column_labels.border.bottom.color = "black",
    column_labels.border.bottom.width = px(2),
    row.striping.include_table_body = TRUE,
    heading.border.bottom.color = "black",
    heading.border.bottom.width = px(2),
    table_body.hlines.color = "gray",
    table_body.border.bottom.color = "black"
  )
Tabla Nro. 1
**Distribucion de frecuencia simplificado de concentración de ozono,estudio calidad del aire en India entre 2015-2020 **
Intervalo ni hi(%)
[0 - 20) 7022 27.53
[20 - 40) 10006 39.23
[40 - 60) 5647 22.14
[60 - 80) 1896 7.43
[80 - 100) 600 2.35
[100 - 120) 224 0.88
[120 - 140) 75 0.29
[140 - 160) 24 0.09
[160 - 180) 11 0.04
[180 - 200) 2 0.01
[200 - 220) 1 0.00
[220 - 240) 0 0.00
[240 - 260) 1 0.00
Totales 25509 100.00
Autor: Grupo 2 Fuente:https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india
# 3. GDF-Histograma de la variable
par(mar = c(5.1, 4.1, 4.1, 2.1))
post<-barplot(TDF_ozonosimplificado$`hi(%)`[1:(nrow(TDF_ozonosimplificado)-1)],
              space = 0,
              col = "skyblue",
              main = "Gráfica N°1:Distribución de la Concentración de Ozono, 
              estudio calidad del aire en India, 2015-2020",
              xlab = "Ozono (µg/m3)",
              ylab = "Porcentaje (%)",
              ylim = c(0,100), xaxt = "n")
limites <- c(post[1] - diff(post)[1]/2,
             post + diff(post)[1]/2)
axis(
  side = 1,
  at = limites,
  labels = round(breaks, 2),
  tck = -0.02
)

# 4. CONJETURA
#Se conjetura que la concentración de ozono sigue un modelo de probabilidad log-normal, ya que la variable en su histograma presenta barras asimétricas hacia la derecha, con una mayor concentración de observaciones en intervalos bajos y una cola larga hacia valores altos, lo que indica una distribución sesgada positiva.

# 5. CÁLCULO DE PARÁMETROS DISTRIBUCIÓN LOG-NORMAL
min(ozono)
## [1] 0.01
log_ozono <- log(ozono)
mulog <- mean(log_ozono)
sigmalog <- sd(log_ozono)

# 6. GDF-HISTOGRAMA DENSIDAD DE PROBABILIDAD 
histozono <- hist(
  ozono,
  breaks = breaks,
  col = "skyblue",
  freq = FALSE,
  main = "Gráfica N°2: Comparación de la Realidad y el Modelo Log-normal
          de la Concentración de Ozono (India, 2015–2020)",
  xlab = " Ozono (µg/m3)",
  ylab = "Densidad de probabilidad",
  cex.main = 0.9, ylim = c(0,0.025)
)
x <- seq(min(ozono), max(ozono), by=0.001)
curve(
  dlnorm(x, meanlog = mulog, sdlog = sigmalog),
  col = "darkblue",
  lwd = 3,
  add = TRUE
)

# 7. TEST DE BONDAD
# Test de Pearson
fo<- ni
fo
##  [1]  7022 10006  5647  1896   600   224    75    24    11     2     1     0
## [13]     1
fe<- N * (plnorm(Ls, mulog, sigmalog) - plnorm(Li, mulog, sigmalog))
Correlación<-cor(fo,fe)*100
Correlación
## [1] 96.73587
#Test de Chi-cuadrado
x2 <- sum((fo - fe)^2 / fe)
x2
## [1] 2194.129
k <- length(fo)
gl <- k - 1 - 2
gl
## [1] 10
umbral_aceptacion <- qchisq(0.9999999999, df = gl)
umbral_aceptacion
## [1] 68.16762
x2<umbral_aceptacion
## [1] FALSE
# 8. OMITIR VALORES ATÍPICOS TEMPORALMETE PARA UN MEJOR AJUSTE DEL MODELO
Cajaozono<-boxplot(ozono, horizontal = T,col = "turquoise", border = "black",
                   main= "Gráfica No. 3: Distribución de la concentración de ozono,
                   estudio calidad del aire en India desde 2015-2020",
                   xlab="Ozono (µg/m3)")

Q1 <- quantile(ozono, 0.25)
Q3 <- quantile(ozono, 0.75)
IQR_ozono <- Q3 - Q1
lim_inf <- Q1 - 1.5 * IQR_ozono
lim_sup <- Q3 + 1.5 * IQR_ozono
ozono_sin_atipicos <- ozono[
  ozono >= lim_inf & ozono <= lim_sup]
length(ozono)          # antes
## [1] 25509
length(ozono_sin_atipicos) # después
## [1] 24796
# 8.2 TDF simplificada
lim_inf <- floor(min(ozono_sin_atipicos) / 10) * 10
lim_sup <- ceiling(max(ozono_sin_atipicos) / 10) * 10
breaks_10 <- seq(lim_inf, lim_sup, by = 10)
#Elemnetos simplificados 
Li <- breaks_10[1:(length(breaks_10)-1)]
Ls <- breaks_10[2:length(breaks_10)]
clases <- cut(
  ozono_sin_atipicos,
  breaks = breaks_10,
  right = FALSE
)
ni <- as.numeric(table(clases))
N<-length(ozono_sin_atipicos)
hi<- (ni / N) * 100
TDF_ozono_sin_atícos <- data.frame(
  Intervalo = paste0("[", round(Li,2), " - ", round(Ls,2), ")"),
  ni = ni,
  hi= round(hi, 2))
colnames(TDF_ozono_sin_atícos) <- c(
  "Intervalo",
  "ni",
  "hi(%)"
)
totales<- data.frame(
  Intervalo = "Totales",
  ni = sum(ni),           # suma total de ni
  hi = sum(hi)
)
colnames(totales) <- c(
  "Intervalo",
  "ni",
  "hi(%)"
)
# Agregar al final de la tabla
TDF_ozono_sin_atícos <- rbind(TDF_ozono_sin_atícos, totales)
TDF_ozono_sin_atícos %>%
  gt() %>%
  tab_header(
    title = md("*Tabla Nro. 2*"),
    subtitle = md("**Distribucion de frecuencia simplificado de concentración de ozono,estudio calidad del aire en India entre 2015-2020 **")
  ) %>%
  tab_source_note(
    source_note = md("Autor: Grupo 2\n Fuente:https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india")
  ) %>%
  tab_options(
    table.border.top.color = "black",
    table.border.bottom.color = "black",
    table.border.top.style = "solid",
    table.border.bottom.style = "solid",
    column_labels.border.top.color = "black",
    column_labels.border.bottom.color = "black",
    column_labels.border.bottom.width = px(2),
    row.striping.include_table_body = TRUE,
    heading.border.bottom.color = "black",
    heading.border.bottom.width = px(2),
    table_body.hlines.color = "gray",
    table_body.border.bottom.color = "black"
  )
Tabla Nro. 2
**Distribucion de frecuencia simplificado de concentración de ozono,estudio calidad del aire en India entre 2015-2020 **
Intervalo ni hi(%)
[0 - 10) 2310 9.32
[10 - 20) 4708 18.99
[20 - 30) 5323 21.47
[30 - 40) 4683 18.89
[40 - 50) 3430 13.83
[50 - 60) 2218 8.94
[60 - 70) 1229 4.96
[70 - 80) 669 2.70
[80 - 90) 226 0.91
Totales 24796 100.00
Autor: Grupo 2 Fuente:https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india
# 8.3 GDF-Histograma de la variable sin valores atípicos
par(mar = c(5.1, 4.1, 4.1, 2.1))
post<-barplot(TDF_ozono_sin_atícos$`hi(%)`[1:(nrow(TDF_ozono_sin_atícos)-1)],
              space = 0,
              col = "skyblue",
              main = "Gráfica N°4:Distribución de la Concentración de Ozono, 
              estudio calidad del aire en India, 2015-2020",
              xlab = "Ozono (µg/m3)",
              ylab = "Porcentaje (%)",
              ylim = c(0,30), xaxt = "n")
limites <- c(post[1] - diff(post)[1]/2,
             post + diff(post)[1]/2)
axis(
  side = 1,
  at = limites,
  labels = round(breaks_10, 2),
  tck = -0.02
)

# 8.4 CONJETURA
#Se conjetura que la concentración de ozono sin valores atípicos sigue un modelo de probabilidad log-normal, ya que la variable en su histograma presenta barras asimétricas hacia la derecha, con una mayor concentración de observaciones en intervalos bajos y una cola larga hacia valores altos, lo que indica una distribución sesgada positiva.

# 8.5 CÁLCULO DE PARÁMETROS DISTRIBUCIÓN LOG-NORMAL
min(ozono_sin_atipicos)
## [1] 0.01
log_ozono_sinatípicos <- log(ozono_sin_atipicos)
mulog <- mean(log_ozono_sinatípicos)
sigmalog <- sd(log_ozono_sinatípicos)

# 8.6 GDF-HISTOGRAMA DENSIDAD DE PROBABILIDAD 
histozono_sinatípicos <- hist(
  ozono_sin_atipicos,
  breaks = breaks_10,
  col = "skyblue",
  freq = FALSE,
  main = "Gráfica N°5: Comparación de la Realidad y el Modelo Log-normal
          de la Concentración de Ozono (India, 2015–2020)",
  xlab = " Ozono (µg/m3)",
  ylab = "Densidad de probabilidad",
  cex.main = 0.9, ylim = c(0,0.030)
)
x <- seq(min(ozono_sin_atipicos), max(ozono_sin_atipicos), by=0.001)
curve(
  dlnorm(x, meanlog = mulog, sdlog = sigmalog),
  col = "darkblue",
  lwd = 3,
  add = TRUE
)

# 8.7 TEST DE BONDAD

# Test de Pearson
fo<- ni
fe<- N * (plnorm(Ls, mulog, sigmalog) - plnorm(Li, mulog, sigmalog))
Correlación<-cor(fo,fe)*100
Correlación
## [1] 90.06752
#Test de Chi-cuadrado
# fo y fe fracción
fo<- (ni/N)
fo
## [1] 0.093160187 0.189869334 0.214671721 0.188861107 0.138328763 0.089449911
## [7] 0.049564446 0.026980158 0.009114373
P<-c(0) 
for (i in 1:9) {P[i] <-(plnorm(Histograma_ozono$breaks[i+1],mulog,
               sigmalog)- plnorm(Histograma_ozono$breaks[i],mulog,sigmalog))}
fe<- P
fe
## [1] 0.362488740 0.344250935 0.150462954 0.067804843 0.032992591 0.017207902
## [7] 0.009511116 0.005516612 0.003331817
x2 <- sum((fo - fe)^2 / fe)
x2
## [1] 1.414686
k <- length(fo)
gl <- k - 1 
gl
## [1] 8
umbral_aceptacion <- qchisq(1- 0.95, df = gl)
umbral_aceptacion
## [1] 2.732637
x2<umbral_aceptacion
## [1] TRUE
# 9. CÁLCULO DE PROBABILIDAD

# ¿Cuál es la probabilidad de que la concentración diaria de ozono se encuentre entre 40 y 50 µg/m³?
plnorm(50, mulog, sigmalog) - plnorm(40, mulog, sigmalog)
## [1] 0.09062237
#¿Cuál es la probabilidad de que la concentración de ozono  no supere los 30 µg/m³?
plnorm(30, mulog, sigmalog)
## [1] 0.5683347
#Demostración:
x <- seq(min(ozono_sin_atipicos), max(ozono_sin_atipicos), by=0.001)
plot(x, dlnorm(x, mulog,sigmalog), col = "skyblue3", lwd = 1, xlim = c(0,100), ylim=c(0,0.030),
     main="Gráfica N°6: Cálculo de probabilidad",
     ylab="Densidad de probabilidad",xlab="Ozono (µg/m3)", xaxt="n")

# Definir el rango de la sección que quieres pintar
x <- seq(40, 50,0.001)
y_section <- dlnorm(x, mulog,sigmalog)

# Pintar la sección de la curva
lines(x, y_section, col = "red", lwd = 2)

# Pintar el área debajo de la línea roja
polygon(c(x, rev(x)), c(y_section, rep(0, length(y_section))), col = rgb(1, 0, 0, 0.6))

x_section2 <- seq(0, 30, by=0.001)
y_section2 <- dlnorm(x_section2, mulog, sigmalog)

lines(x_section2, y_section2, col="green", lwd=2)

polygon(c(x_section2, rev(x_section2)),
        c(y_section2, rep(0, length(y_section2))),
        col=rgb(0,1,0,0.4))  # verde semi-transparente
# Añadir leyenda
legend("topright", legend = c("Modelo", "Área de Probabilidad","Área de Probabilidad"), col = c("skyblue3", "red","green"), lwd = 2, pch = c(NA, 15))

# Ajustar la escala del eje x a intervalos de 25
axis(1, at = seq(0, 250, by = 10), labels = seq(0, 250, by = 10), las = 2)