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")

1. Extraer y Depuración de la Variable

#depuración

variables <-na.omit(variables)

# selección

CO <- variables$air_quality_Carbon_Monoxide

# Total de datos

n_total <- length(CO)

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)
  }
}

# Frecuencia relativa
hi1 <- (ni1 / sum(ni1)) * 100

# Acumuladas
Ni_asc1 <- cumsum(ni1)
Hi_asc1 <- cumsum(hi1)

Ni_dsc1 <- rev(cumsum(rev(ni1)))
Hi_dsc1 <- rev(cumsum(rev(hi1)))

# Marca de clase
MC1 <- (Li1 + Ls1)/2

3.5. Amplitud para tabla ajustada

# Intervalos
 
K_ajustado <- 10
amplitud <- ceiling(rango / K_ajustado) # Redondeo superior para asegurar cobertura limpia

Li2 <- seq(floor(valor_min), by = amplitud, length.out = K_ajustado)
Ls2 <- Li2 + amplitud

ni2 <- numeric(length(Li2))
for(i in 1:length(Li2)){
  if(i == length(Li2)){
    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)
  }
}


# Frecuencia relativa
hi2 <- (ni2 / sum(ni2)) * 100

# Acumuladas
Ni_asc2 <- cumsum(ni2)
Hi_asc2 <- cumsum(hi2)

Ni_dsc2 <- rev(cumsum(rev(ni2)))
Hi_dsc2 <- rev(cumsum(rev(hi2)))



# Marca de clase
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_total <- 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_total)

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") |> # Azul Turquesa Pastel
  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
-9999 -7283.53 -8641.27 1 0 1 0 141703 100
-7283.53 -4568.07 -5925.8 0 0 1 0 141702 100
-4568.07 -1852.6 -3210.33 0 0 1 0 141702 100
-1852.6 862.87 -494.87 129757 91.57 129758 91.57 141702 100
862.87 3578.33 2220.6 10823 7.64 140581 99.21 11945 8.43
3578.33 6293.8 4936.07 709 0.5 141290 99.71 1122 0.79
6293.8 9009.27 7651.53 248 0.18 141538 99.88 413 0.29
9009.27 11724.73 10367 101 0.07 141639 99.95 165 0.12
11724.73 14440.2 13082.47 36 0.03 141675 99.98 64 0.05
14440.2 17155.67 15797.93 7 0 141682 99.99 28 0.02
17155.67 19871.13 18513.4 6 0 141688 99.99 21 0.01
19871.13 22586.6 21228.87 2 0 141690 99.99 15 0.01
22586.6 25302.07 23944.33 2 0 141692 99.99 13 0.01
25302.07 28017.53 26659.8 2 0 141694 99.99 11 0.01
28017.53 30733 29375.27 4 0 141698 100 9 0.01
30733 33448.46 32090.73 1 0 141699 100 5 0
33448.46 36163.93 34806.2 2 0 141701 100 4 0
36163.93 38879.4 37521.66 2 0 141703 100 2 0
TOTAL 141703 100
Nota: Elaborado por Grupo 2.
Fuente: Global Weather Repository.

4.1. Tabla ajustada

TDF_CO <- data.frame(
  Lim_inf = round(Li2, 2), Lim_sup = round(Ls2, 2), MC = round(MC2, 2),
  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) de los registros meteorológicos mundiales, período 2024–2026") |> 
  kable_styling(full_width = TRUE, position = "center", bootstrap_options = c("striped", "hover", "condensed", "responsive")) |> 
  row_spec(0, bold = TRUE, color = "black", background = "#C8E6C9") |> # Verde Menta Pastel
  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) de los registros meteorológicos mundiales, período 2024–2026
Lim. Inf. Lim. Sup. MC ni hi (%) Ni Asc Hi Asc Ni Dsc Hi Dsc
-9999 -5111 -7555 1 0 1 0 141703 100
-5111 -223 -2667 0 0 1 0 141702 100
-223 4665 2221 140981 99.49 140982 99.49 141702 100
4665 9553 7109 581 0.41 141563 99.9 721 0.51
9553 14441 11997 112 0.08 141675 99.98 140 0.1
14441 19329 16885 11 0.01 141686 99.99 28 0.02
19329 24217 21773 5 0 141691 99.99 17 0.01
24217 29105 26661 5 0 141696 100 12 0.01
29105 33993 31549 4 0 141700 100 7 0
33993 38881 36437 3 0 141703 100 3 0
TOTAL 141703 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, 
  main = "Grafico Nro 1: Histograma y polígono frecuencias absolutas del\nMonóxido de Carbono (CO), período 2024 a 2026", 
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia", 
  col = "#FFECB3", border = "white" # Amarillo pastel suave
 )

grid()

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

hist(
  CO, 
  breaks = c(Li2, max(Ls2)), ylim = c(0, n_total),
  main = "Grafico Nro 2: Histograma global de Monóxido de Carbono (CO) respecto al 
  tamaño muestral", 
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia", 
  col = "#D1C4E9", border = "white" # Morado pastel suave
)
grid()

5.3. Histograma original (hi)

barplot(
  hi2, names.arg = paste(Li2, Ls2, sep = " a "),
  main = "Grafico Nro 3: Histograma local de frecuencia relativa de CO\nPeriodo 2024 - 2026",
  xlab = "Intervalos de CO", ylab = "Frecuencia Relativa (%)", 
  col = "#F8BBD0", border = "white", las = 2, cex.names = 0.7
)

5.4. Histograma con relacion a todo (hi)

barplot(
  hi2, names.arg = paste(Li2, Ls2, sep = " a "), ylim = c(0, 100),
  main = "Grafico Nro 4: Histograma global de frecuencia relativa de CO\n(Escala 0% - 100%)", 
  xlab = "Intervalos de CO", ylab = "Frecuencia Relativa (%)", 
  col = "#B2DFDB", border = "white", las = 2, cex.names = 0.7
)

5.5. Polígono de frecuencias (hi)

bp <- barplot(
  hi2, names.arg = paste(Li2, Ls2, sep = "-"),
  col = "#C8E6C9", border = "white", ylim = c(0, max(hi2)*1.2), 
  main = "Grafico Nro 5: Polígono de frecuencias relativas de la concentración\nde Monóxido de Carbono (CO), período 2024–2026",
  xlab = "Intervalos", ylab = "Frecuencia relativa (%)", las = 2, cex.names = 0.7
)
x_pol <- c(bp[1] - (bp[2]-bp[1]), bp, bp[length(bp)] + (bp[2]-bp[1]))
y_pol <- c(0, hi2, 0)
lines(x_pol, y_pol, type = "o", col = "#FF7043", lwd = 2, pch = 16) # Línea Coral fuerte para contraste
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)),
  main = "Grafico Nro 6: Ojivas de Frecuencia Absoluta Acumulada de CO\nPeriodo 2024-2026", 
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia Acumulada (Ni)"
)
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),
  xlab = "Monóxido de Carbono (CO)", ylab = "Frecuencia Relativa Acumulada (%)", 
  main = "Grafico Nro 7: Ojivas de frecuencias relativas acumuladas\ndel Monóxido de Carbono (CO), período 2024–2026"
)
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

Q1 <- quantile(CO, 0.25)
Q3 <- quantile(CO, 0.75)
RIC <- Q3 - Q1
Lim_inf <- Q1 - 1.5 * RIC
Lim_sup <- Q3 + 1.5 * RIC
boxplot(
  CO, horizontal = TRUE, outline = FALSE, 
  main = "Gráfico Nro 8: Boxplot de Monóxido de Carbono (CO)\ período 2024-2026", 
  xlab = "CO", col = "#CFD8DC"
)
atipicos <- CO[CO < Lim_inf | CO > Lim_sup]
if(length(atipicos) > 0) {
  # Graficamos una muestra representativa de atípicos para no saturar el lienzo gráfico
  set.seed(123)
  muestra_atipicos <- sample(atipicos, min(length(atipicos), 1000))
  points(muestra_atipicos, rep(1, length(muestra_atipicos)), col = "#FF5252", pch = 19, cex = 0.5)
}
abline(v = Lim_inf, col = "#1E88E5", lwd = 2, lty = 2)
abline(v = Lim_sup, col = "#1E88E5", lwd = 2, lty = 2)
legend("topright", legend = c("Atípicos (Muestra)", "Límites de Tukey"),
       col = c("#FF5252", "#1E88E5"), pch = c(19, NA), lty = c(NA, 2), lwd = c(NA, 2), bty = "n")
grid()

6. Indicadores Estadísticos

6.1. Tendencia central

media <- mean(CO)

mediana <- median(CO)
max_ni <- max(TDF_CO$ni)
moda <- TDF_CO$MC[TDF_CO$ni == max_ni]

6.1. Dispersión

varianza <- var(CO)
desv_est <- sd(CO)
cv <- (desv_est / media) * 100

6.3. Forma

asimetria <- skewness(CO)
curtosis <- kurtosis(CO)

6.4. Valores atípicos

n_atipicos <- length(atipicos)
rango_texto <- paste0("[", round(min(CO),2), "; ", round(max(CO),2), "]")

6.5. Tabla de indicadores

tabla_indicadores <- data.frame(
  Variable = "Monóxido de Carbono (CO)",
  Rango = rango_texto,
  Media = round(media,2),
  Mediana = round(mediana,2),
  Moda = round(moda[1],2), 
  Varianza = round(varianza,2),
  Desv_Est = round(desv_est,2),
  CV = round(cv,2),
  Asimetria = round(asimetria,2),
  Curtosis = round(curtosis,2),
  N_Atipicos = n_atipicos
)

kable(tabla_indicadores, align = "c", 
      caption = "Tabla N°3: Indicadores estadísticos descriptivos de la variable Monóxido de Carbono (CO) mediante registros meteorológicos mundiales, período 2024–2026") |>
  kable_styling(full_width = TRUE, position = "center", bootstrap_options = c("striped", "hover", "condensed", "responsive")) |>
  row_spec(0, bold = TRUE, color = "black", background = "#D1C4E9") # Lila Pastel
Tabla N°3: Indicadores estadísticos descriptivos de la variable Monóxido de Carbono (CO) mediante registros meteorológicos mundiales, período 2024–2026
Variable Rango Media Mediana Moda Varianza Desv_Est CV Asimetria Curtosis N_Atipicos
Monóxido de Carbono (CO) [-9999; 38879.4] 451.86 288.6 2221 556583.8 746.05 165.11 13.33 364.09 12626

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 = 288.6 ppm).”, “No obstante, el comportamiento de los datos refleja una marcada asimetría positiva (13.33)”, “y una dispersión extrema (CV = 165.11%) introducida por 12,626”, “registros atípicos, los cuales evidencian episodios críticos y puntuales de contaminación atmosférica.”