0. Librerias

library(readr)
library(dplyr)
library(knitr)
library(kableExtra)
library(ggplot2)
library(e1071)
library(moments)

1. Leer Datos

variables <- read.csv("C:/Users/dellh/Downloads/GlobalWeatherRepository.csv")

2. Extraer y Depuración de la Variable

# Depuración 
variables <- na.omit(variables)

# Extracción de la variable y cálculo del tamaño inicial
CO_raw <- variables$air_quality_Carbon_Monoxide
n_inicial <- length(CO_raw)

# Regla de Tukey (RIC) para filtrar valores atípicos
Q1 <- quantile(CO_raw, 0.25, na.rm = TRUE)
Q3 <- quantile(CO_raw, 0.75, na.rm = TRUE)
RIC <- Q3 - Q1

limite_inferior <- Q1 - 1.5 * RIC
limite_superior <- Q3 + 1.5 * RIC

# Filtrado de la variable
CO <- CO_raw[CO_raw >= limite_inferior & CO_raw <= limite_superior]

# Recuentos finales
n_total <- length(CO)
n_atipicos_removidos <- n_inicial - n_total
pct_atipicos_removidos <- round((n_atipicos_removidos / n_inicial) * 100, 2)

3. Frecuencias

3.1 Max y Min

valor_min <- min(CO, na.rm = TRUE)
valor_max <- max(CO, na.rm = TRUE)
rango <- valor_max - valor_min

3.2. Regla de Sturges

K_sturges <- floor(1 + 3.322 * log10(n_total))

A_sturges <- rango / K_sturges

3.3. Intervalos

Li1 <- seq(valor_min, valor_max - A_sturges, by = A_sturges)
Ls1 <- Li1 + A_sturges

3.4. Bucle para las columnas de la tabla

ni1 <- numeric(length(Li1))
for(i in 1:length(Li1)){
  if(i == length(Li1)){
    ni1[i] <- sum(CO >= Li1[i] & CO <= Ls1[i], na.rm = TRUE)
  } else {
    ni1[i] <- sum(CO >= Li1[i] & CO < Ls1[i], na.rm = TRUE)
  }
}

hi1 <- (ni1 / sum(ni1)) * 100
Ni_asc1 <- cumsum(ni1)
Hi_asc1 <- cumsum(hi1)
Ni_dsc1 <- rev(cumsum(rev(ni1)))
Hi_dsc1 <- rev(cumsum(rev(hi1)))
MC1 <- (Li1 + Ls1) / 2

3.5. Amplitud para tabla ajustada

# Intervalos

K_ajustado <- 10
amplitud <- 80
valor_min_limpio <- 50  # Mínimo redondeado para empezar limpio

Li2 <- seq(valor_min_limpio, by = amplitud, length.out = K_ajustado)
Ls2 <- Li2 + amplitud
cortes2 <- c(Li2, Ls2[K_ajustado]) # Vector: 50, 130, 210, 290, 370, 450, 530, 610, 690, 770, 850

ni2 <- numeric(K_ajustado)
for(i in 1:K_ajustado){
  if(i == K_ajustado){
    ni2[i] <- sum(CO >= Li2[i] & CO <= Ls2[i], na.rm = TRUE)
  } else {
    ni2[i] <- sum(CO >= Li2[i] & CO < Ls2[i], na.rm = TRUE)
  }
}

hi2 <- (ni2 / sum(ni2)) * 100
Ni_asc2 <- cumsum(ni2)
Hi_asc2 <- cumsum(hi2)
Ni_dsc2 <- rev(cumsum(rev(ni2)))
Hi_dsc2 <- rev(cumsum(rev(hi2)))
MC2 <- (Li2 + Ls2) / 2

4. Tabla de Distribución de Frecuencias

4.1. Tabla 1

Tabla_Sturges <- data.frame(
  Lim_inf = round(Li1, 2), Lim_sup = round(Ls1, 2), MC = round(MC1, 2),
  ni = ni1, hi = round(hi1, 2), Ni_asc = Ni_asc1, Hi_asc = round(Hi_asc1, 2),
  Ni_dsc = Ni_dsc1, Hi_dsc = round(Hi_dsc1, 2)
)
Tabla_Sturges2 <- Tabla_Sturges
Tabla_Sturges2[] <- lapply(Tabla_Sturges2, as.character)
fila_total1 <- data.frame(
  Lim_inf = "TOTAL", Lim_sup = "", MC = "",
  ni = as.character(sum(ni1)), hi = as.character(round(sum(hi1), 2)),
  Ni_asc = "-", Hi_asc = "-", Ni_dsc = "-", Hi_dsc = "-"
)
Tabla_Sturges2 <- rbind(Tabla_Sturges2, fila_total1)

kable(Tabla_Sturges2, align = "c",
      caption = "Tabla N°1: Distribución de frecuencias de los niveles de Monóxido de Carbono (CO) a nivel global durante el período 2024–2026") |> 
  kableExtra::kable_styling(full_width = TRUE, position ="center", bootstrap_options = c("striped", "hover", "condensed", "responsive")) |> 
  kableExtra::row_spec(0, bold = TRUE, color = "black", background = "#B2EBF2") |> 
  kableExtra::row_spec(nrow(Tabla_Sturges2), bold = TRUE, background = "#EAEDED") |> 
  footnote(general = "Elaborado por Grupo 2.\nFuente: Global Weather Repository.", general_title = "Nota:", footnote_as_chunk = TRUE, title_format = c("italic","bold"))
Tabla N°1: Distribución de frecuencias de los niveles de Monóxido de Carbono (CO) a nivel global durante el período 2024–2026
Lim_inf Lim_sup MC ni hi Ni_asc Hi_asc Ni_dsc Hi_dsc
53.85 99.91 76.88 3155 2.44 3155 2.44 129072 100
99.91 145.97 122.94 10100 7.83 13255 10.27 125917 97.56
145.97 192.03 169 20158 15.62 33413 25.89 115817 89.73
192.03 238.09 215.06 19285 14.94 52698 40.83 95659 74.11
238.09 284.14 261.11 16638 12.89 69336 53.72 76374 59.17
284.14 330.2 307.17 14619 11.33 83955 65.05 59736 46.28
330.2 376.26 353.23 10795 8.36 94750 73.41 45117 34.95
376.26 422.32 399.29 7589 5.88 102339 79.29 34322 26.59
422.32 468.38 445.35 5871 4.55 108210 83.84 26733 20.71
468.38 514.44 491.41 4804 3.72 113014 87.56 20862 16.16
514.44 560.5 537.47 3686 2.86 116700 90.41 16058 12.44
560.5 606.56 583.53 3099 2.4 119799 92.82 12372 9.59
606.56 652.61 629.59 2582 2 122381 94.82 9273 7.18
652.61 698.67 675.64 2102 1.63 124483 96.44 6691 5.18
698.67 744.73 721.7 1734 1.34 126217 97.79 4589 3.56
744.73 790.79 767.76 1569 1.22 127786 99 2855 2.21
790.79 836.85 813.82 1286 1 129072 100 1286 1
TOTAL 129072 100
Nota: Elaborado por Grupo 2.
Fuente: Global Weather Repository.

4.2. Tabla ajustada

TDF_CO <- data.frame(
  Lim_inf = Li2, Lim_sup = Ls2, MC = MC2,
  ni = ni2, hi = round(hi2, 2), Ni_asc = Ni_asc2, Hi_asc = round(Hi_asc2, 2),
  Ni_dsc = Ni_dsc2, Hi_dsc = round(Hi_dsc2, 2)
)
TDF_CO_Texto <- TDF_CO
TDF_CO_Texto[] <- lapply(TDF_CO_Texto, as.character)
TDF_Total <- data.frame(
  Lim_inf = "TOTAL", Lim_sup = "", MC = "",
  ni = as.character(sum(ni2)), hi = as.character(round(sum(hi2), 2)),
  Ni_asc = "-", Hi_asc = "-", Ni_dsc = "-", Hi_dsc = "-",
  stringsAsFactors = FALSE
)
TDF_CO_Final <- rbind(TDF_CO_Texto, TDF_Total)
colnames(TDF_CO_Final) <- c("Lim. Inf.", "Lim. Sup.", "MC", "ni", "hi (%)", "Ni Asc", "Hi Asc", "Ni Dsc", "Hi Dsc")

kable(TDF_CO_Final, align = "c",
      caption = "Tabla N°2: Distribución de frecuencias para Monóxido de Carbono (CO) depurado (Amplitud c = 80)") |> 
  kable_styling(full_width = TRUE, position = "center", bootstrap_options = c("striped", "hover", "condensed", "responsive")) |> 
  row_spec(0, bold = TRUE, color = "black", background = "#C8E6C9") |> 
  row_spec(nrow(TDF_CO_Final), bold = TRUE, background = "#EAEDED") |> 
  footnote(general = "Elaborado por Grupo 2.\nFuente: Global Weather Repository.", general_title = "Nota: ", footnote_as_chunk = TRUE, title_format = c("italic","bold"))
Tabla N°2: Distribución de frecuencias para Monóxido de Carbono (CO) depurado (Amplitud c = 80)
Lim. Inf. Lim. Sup. MC ni hi (%) Ni Asc Hi Asc Ni Dsc Hi Dsc
50 130 90 8529 6.61 8529 6.61 129077 100
130 210 170 32582 25.24 41111 31.85 120548 93.39
210 290 250 30091 23.31 71202 55.16 87966 68.15
290 370 330 22130 17.14 93332 72.31 57875 44.84
370 450 410 12636 9.79 105968 82.1 35745 27.69
450 530 490 8350 6.47 114318 88.57 23109 17.9
530 610 570 5735 4.44 120053 93.01 14759 11.43
610 690 650 4057 3.14 124110 96.15 9024 6.99
690 770 730 3039 2.35 127149 98.51 4967 3.85
770 850 810 1928 1.49 129077 100 1928 1.49
TOTAL 129077 100
Nota: Elaborado por Grupo 2.
Fuente: Global Weather Repository.

5. Gráficos de Distribución de Frecuencias

5.1. Histograma Original (ni)

hist(
  CO, 
  breaks = cortes2,
  xaxt = "n",
  main = "Gráfico Nro 1: Histograma de frecuencias absolutas del\nMonóxido de Carbono (CO)", 
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia (ni)", 
  col = "#FFECB3", border = "black"
)
axis(1, at = cortes2, las = 2, cex.axis = 0.8)
grid()

5.2. Histograma con relación al todo (ni)

hist(
  CO, 
  breaks = cortes2, 
  ylim = c(0, n_total),
  xaxt = "n",
  main = "Gráfico Nro 2: Histograma global de Monóxido de Carbono (CO) respecto al\ntamaño muestral", 
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia (ni)", 
  col = "#D1C4E9", border = "black"
)
axis(1, at = cortes2, las = 2, cex.axis = 0.8)
grid()

5.3. Histograma de Frecuencia Relativa (hi)

h_rel <- hist(CO, breaks = cortes2, plot = FALSE)
h_rel$counts <- (h_rel$counts / sum(h_rel$counts)) * 100

plot(
  h_rel, 
  freq = TRUE,
  xaxt = "n",
  main = "Gráfico Nro 3: Histograma local de frecuencia relativa de CO (%)",
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia Relativa (%)", 
  col = "#F8BBD0", border = "black"
)
axis(1, at = cortes2, las = 2, cex.axis = 0.8)
grid()

5.4. Histograma Global (hi)

plot(
  h_rel, 
  freq = TRUE, 
  ylim = c(0, 100),
  xaxt = "n",
  main = "Gráfico Nro 4: Histograma global de frecuencia relativa de CO (0% - 100%)", 
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia Relativa (%)", 
  col = "#B2DFDB", border = "black"
)
axis(1, at = cortes2, las = 2, cex.axis = 0.8)
grid()

5.5. Polígono de frecuencias (hi)

plot(
  h_rel, 
  freq = TRUE, 
  ylim = c(0, max(hi2) * 1.2),
  xaxt = "n",
  main = "Gráfico Nro 5: Polígono de frecuencias relativas de CO (%)",
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia relativa (%)", 
  col = "#C8E6C9", border = "black"
)
axis(1, at = cortes2, las = 2, cex.axis = 0.8)

x_pol <- c(MC2[1] - amplitud, MC2, MC2[length(MC2)] + amplitud)
y_pol <- c(0, hi2, 0)
lines(x_pol, y_pol, type = "o", col = "#FF7043", lwd = 2, pch = 16)
grid()

5.6. Ojiva ascendente y descendente (ni)

plot(
  Ls2, Ni_asc2, type = "o", pch = 16, lwd = 2, col = "#4FC3F7", ylim = c(0, max(Ni_asc2)),
  xaxt = "n",
  main = "Gráfico Nro 6: Ojivas de Frecuencia Absoluta Acumulada (Ni)", 
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia Acumulada (Ni)"
)
axis(1, at = cortes2, las = 2, cex.axis = 0.8)
lines(Li2, Ni_dsc2, type = "o", pch = 17, lwd = 2, col = "#FF8A80")
legend("right", legend = c("Ojiva Ascendente", "Ojiva Descendente"),
       col = c("#4FC3F7", "#FF8A80"), pch = c(16, 17), lwd = 2, bty = "n")
grid()

5.7. Ojiva ascentende y descendente (hi)

plot(
  Ls2, Hi_asc2, type = "o", pch = 16, col = "#4FC3F7", lwd = 2, ylim = c(0, 100),
  xaxt = "n",
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia Relativa Acumulada (%)", 
  main = "Gráfico Nro 7: Ojivas de frecuencias relativas acumuladas (%)"
)
axis(1, at = cortes2, las = 2, cex.axis = 0.8)
lines(Li2, Hi_dsc2, type = "o", pch = 17, col = "#FF8A80", lwd = 2)
legend("right", legend = c("Ojiva Ascendente", "Ojiva Descendente"),
       col = c("#4FC3F7", "#FF8A80"), pch = c(16, 17), lwd = 2, bty = "n")
grid()

5.8. Bloxplot

boxplot(
  CO, horizontal = TRUE, 
  main = "Gráfico Nro 8: Boxplot de Monóxido de Carbono (CO) sin atípicos\nperiodo 2024-2026", 
  xlab = "CO", col = "#CFD8DC"
)
abline(v = min(CO), col = "#1E88E5", lwd = 2, lty = 2)
abline(v = max(CO), col = "#1E88E5", lwd = 2, lty = 2)
legend("topright", legend = "Límites del Rango Depurado",
       col = "#1E88E5", lty = 2, lwd = 2, bty = "n")
grid()

6. Indicadores Estadísticos

6.1. Tendencia central

media <- mean(CO, na.rm = TRUE)
mediana <- median(CO, na.rm = TRUE)

max_ni <- max(TDF_CO$ni)
modas_mc <- TDF_CO$MC[TDF_CO$ni == max_ni]
moda_texto <- paste(round(modas_mc, 2), collapse = ", ")

6.1. Dispersión

varianza <- var(CO, na.rm = TRUE)
desv_est <- sd(CO, na.rm = TRUE)
cv <- (desv_est / media) * 100

6.3. Forma

asimetria <- skewness(CO, na.rm = TRUE)
curtosis <- kurtosis(CO, na.rm = TRUE)

6.4. Valores atípicos

rango_texto <- paste0("[", round(valor_min, 2), " ; ", round(valor_max, 2), "]")

6.5. Tabla de indicadores

tabla_indicadores <- data.frame(
  Indicador = c("Muestra Inicial (n)", "Atípicos Filtrados (n)", "Atípicos Filtrados (%)",
                "Muestra Depurada (n)", "Rango de Datos", "Media", "Mediana", "Moda (MC)", 
                "Varianza", "Desviación Estándar", "Coef. de Variación (%)", 
                "Asimetría", "Curtosis"),
  Valor = c(n_inicial, 
            n_atipicos_removidos, 
            paste0(pct_atipicos_removidos, "%"),
            n_total,
            rango_texto, 
            round(media, 2), 
            round(mediana, 2), 
            moda_texto, 
            round(varianza, 2), 
            round(desv_est, 2), 
            paste0(round(cv, 2), "%"), 
            round(asimetria, 2), 
            round(curtosis, 2))
)

kable(tabla_indicadores, align = "c", 
      col.names = c("Indicador Estadístico", "Valor Calculado"),
      caption = "Tabla N°3: Resumen de indicadores descriptivos de Monóxido de Carbono (CO) depurado, período 2024–2026") |>
  kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover", "condensed", "responsive")) |>
  row_spec(0, bold = TRUE, color = "black", background = "#D1C4E9") |>
  footnote(general = "Elaborado por Grupo 2.\nFuente: Global Weather Repository.", general_title = "Nota: ", footnote_as_chunk = TRUE, title_format = c("italic","bold"))
Tabla N°3: Resumen de indicadores descriptivos de Monóxido de Carbono (CO) depurado, período 2024–2026
Indicador Estadístico Valor Calculado
Muestra Inicial (n) 141703
Atípicos Filtrados (n) 12626
Atípicos Filtrados (%) 8.91%
Muestra Depurada (n) 129077
Rango de Datos [53.85 ; 836.85]
Media 310.28
Mediana 270.1
Moda (MC) 170
Varianza 26197.09
Desviación Estándar 161.86
Coef. de Variación (%) 52.16%
Asimetría 1.1
Curtosis 3.73
Nota: Elaborado por Grupo 2.
Fuente: Global Weather Repository.

7. Conclusiones

El análisis del Monóxido de Carbono (CO) demuestra que la calidad del aire se mantiene en niveles saludables y notablemente estables la mayor parte del tiempo (Mediana = 270.1 ppm). No obstante, el comportamiento de los datos refleja una asimetría positiva (1.1) y una dispersión moderada (CV = 52.16%) introducida por 12,626 registros atípicos (8.91%), los cuales evidencian episodios críticos y puntuales de contaminación atmosférica dañinos para la salud humana y el medio ambiente.