title: “ESTUDIO ESTADÍSTICO DE LA CALIDAD DEL AIRE EN INDIA” output:
html_notebook — # UNIVERSIDAD CENTRAL DEL ECUADOR ### PROYECTO:ESTUDIO
ESTADÍSTICO DE LA CALIDAD DEL AIRE EN INDIA ### FECHA: 21/11/2025
# ========================================================
# ESTADÍSTICA Inferencial
# Ariana Viteri
# 04/01/2025
# ========================================================
# 1. CARGA DE PAQUETES Y DATOS
library(gt)
library(dplyr)
# Carga de datos
# El archivo ya está cargado en el entorno
datos <- read.csv("~/ariana tercer semestre/Estadistica/city_day.csv", # ¡ATENCIÓN! Ruta cambiada para usar el archivo cargado.
header = TRUE,
sep = ",",
dec = ".")
# ==============================================================================
# 2. PREPARACIÓN Y LIMPIEZA DE DATOS DE MATERIA PARTICULADA PM2.5
# ==============================================================================
# Extracción de los "-" (valores inexistentes) de la variable PM2.5
# Usando la notación de corchetes con el nombre de la columna que contiene el punto
pm25 <- datos$PM2.5[datos$PM2.5 != "-"]
# Tamaño muestral después de la limpieza
cat("Tamaño muestral de la Materia Particulada PM2.5 (sin '-'):", length(pm25), "\n")
## Tamaño muestral de la Materia Particulada PM2.5 (sin '-'): 24933
# Conversión a numérico
pm25 <- as.numeric(pm25)
# ==============================================================================
# 3. CÁLCULOS PARA LA DISTRIBUCIÓN DE FRECUENCIAS DETALLADA (34 CLASES)
# ==============================================================================
N <- length(pm25)
min_pm25 <- min(pm25)
max_pm25 <- max(pm25)
R <- max_pm25 - min_pm25
# Número de clases (k): Se mantienen 34 clases para replicar la estructura original
k_detallado <- 34
# Amplitud de clase (A)
A <- R / k_detallado
# Generación de límites de intervalos
Li <- seq(from = min_pm25, to = max_pm25 - A, by = A)
Ls <- c(seq(from = min_pm25 + A, to = max_pm25 - A, by = A), max_pm25)
# Redondeo para cálculos de intervalos precisos
pm25 <- round(pm25, 3)
Li <- round(Li, 3)
Ls <- round(Ls, 3)
# Marcas de Clase (MC)
MC <- (Li + Ls) / 2
# Creación de frecuencias absolutas (ni)
ni <- numeric(length(Li))
for (i in 1:length(Li)) {
if (i < length(Li)) {
# Intervalo abierto por la derecha: [Li, Ls)
ni[i] <- sum(pm25 >= Li[i] & pm25 < Ls[i])
} else {
# Último intervalo cerrado: [Li, Ls]
ni[i] <- sum(pm25 >= Li[i] & pm25 <= Ls[i])
}
}
# Frecuencias relativas y acumuladas
hi <- (ni / N) * 100
Ni_asc <- cumsum(ni)
Ni_desc <- rev(cumsum(rev(ni)))
Hi_asc <- cumsum(hi)
Hi_desc <- rev(cumsum(rev(hi)))
# Formatear la columna Intervalo
Intervalo <- paste0("[", round(Li, 2), " - ", round(Ls, 2), ")")
# Corregir el último intervalo para que sea cerrado
Intervalo[length(Intervalo)] <- paste0("[", round(Li[length(Li)], 2), " - ",
round(Ls[length(Ls)], 2), "]")
# Crear el Data Frame (TDF)
TDF_pm25 <- data.frame(
Intervalo = Intervalo,
MC = round(MC, 2),
ni = ni,
hi = round(hi, 2),
Ni_ascendente = Ni_asc,
Ni_descendente = Ni_desc,
Hi_ascendente = round(Hi_asc, 2),
Hi_descendente = round(Hi_desc, 2)
)
# Agregar la fila de totales
totales <- data.frame(
Intervalo = "Totales",
MC = "-",
ni = sum(ni),
hi = sum(hi),
Ni_ascendente = "-",
Ni_descendente = "-",
Hi_ascendente = "-",
Hi_descendente = "-"
)
TDF_pm25_completa <- rbind(TDF_pm25, totales)
# ==============================================================================
# 4. TABLA DE FRECUENCIAS DETALLADA (Tabla Nro. 1)
# ==============================================================================
TDF_pm25_completa %>%
gt() %>%
tab_header(
title = "Tabla Nro. 1",
subtitle = "Distribución de frecuencia de concentración de Materia Particulada (PM2.5), estudio calidad del aire en India entre 2015-2020"
) %>%
tab_source_note(
source_note = "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 |
| Distribución de frecuencia de concentración de Materia Particulada (PM2.5), estudio calidad del aire en India entre 2015-2020 |
| Intervalo |
MC |
ni |
hi |
Ni_ascendente |
Ni_descendente |
Hi_ascendente |
Hi_descendente |
| [0.04 - 27.98) |
14.01 |
5946 |
23.85 |
5946 |
24933 |
23.85 |
100 |
| [27.98 - 55.92) |
41.95 |
8318 |
33.36 |
14264 |
18987 |
57.21 |
76.15 |
| [55.92 - 83.86) |
69.89 |
4831 |
19.38 |
19095 |
10669 |
76.59 |
42.79 |
| [83.86 - 111.8) |
97.83 |
2178 |
8.74 |
21273 |
5838 |
85.32 |
23.41 |
| [111.8 - 139.74) |
125.77 |
1159 |
4.65 |
22432 |
3660 |
89.97 |
14.68 |
| [139.74 - 167.68) |
153.71 |
753 |
3.02 |
23185 |
2501 |
92.99 |
10.03 |
| [167.68 - 195.62) |
181.65 |
533 |
2.14 |
23718 |
1748 |
95.13 |
7.01 |
| [195.62 - 223.56) |
209.59 |
370 |
1.48 |
24088 |
1215 |
96.61 |
4.87 |
| [223.56 - 251.5) |
237.53 |
284 |
1.14 |
24372 |
845 |
97.75 |
3.39 |
| [251.5 - 279.44) |
265.47 |
177 |
0.71 |
24549 |
561 |
98.46 |
2.25 |
| [279.44 - 307.38) |
293.41 |
122 |
0.49 |
24671 |
384 |
98.95 |
1.54 |
| [307.38 - 335.32) |
321.35 |
55 |
0.22 |
24726 |
262 |
99.17 |
1.05 |
| [335.32 - 363.26) |
349.29 |
59 |
0.24 |
24785 |
207 |
99.41 |
0.83 |
| [363.26 - 391.2) |
377.23 |
38 |
0.15 |
24823 |
148 |
99.56 |
0.59 |
| [391.2 - 419.14) |
405.17 |
25 |
0.10 |
24848 |
110 |
99.66 |
0.44 |
| [419.14 - 447.08) |
433.11 |
21 |
0.08 |
24869 |
85 |
99.74 |
0.34 |
| [447.08 - 475.02) |
461.04 |
17 |
0.07 |
24886 |
64 |
99.81 |
0.26 |
| [475.02 - 502.96) |
488.98 |
10 |
0.04 |
24896 |
47 |
99.85 |
0.19 |
| [502.96 - 530.89) |
516.92 |
6 |
0.02 |
24902 |
37 |
99.88 |
0.15 |
| [530.89 - 558.83) |
544.86 |
6 |
0.02 |
24908 |
31 |
99.9 |
0.12 |
| [558.83 - 586.77) |
572.8 |
4 |
0.02 |
24912 |
25 |
99.92 |
0.1 |
| [586.77 - 614.71) |
600.74 |
2 |
0.01 |
24914 |
21 |
99.92 |
0.08 |
| [614.71 - 642.65) |
628.68 |
2 |
0.01 |
24916 |
19 |
99.93 |
0.08 |
| [642.65 - 670.59) |
656.62 |
2 |
0.01 |
24918 |
17 |
99.94 |
0.07 |
| [670.59 - 698.53) |
684.56 |
2 |
0.01 |
24920 |
15 |
99.95 |
0.06 |
| [698.53 - 726.47) |
712.5 |
1 |
0.00 |
24921 |
13 |
99.95 |
0.05 |
| [726.47 - 754.41) |
740.44 |
1 |
0.00 |
24922 |
12 |
99.96 |
0.05 |
| [754.41 - 782.35) |
768.38 |
0 |
0.00 |
24922 |
11 |
99.96 |
0.04 |
| [782.35 - 810.29) |
796.32 |
0 |
0.00 |
24922 |
11 |
99.96 |
0.04 |
| [810.29 - 838.23) |
824.26 |
3 |
0.01 |
24925 |
11 |
99.97 |
0.04 |
| [838.23 - 866.17) |
852.2 |
1 |
0.00 |
24926 |
8 |
99.97 |
0.03 |
| [866.17 - 894.11) |
880.14 |
1 |
0.00 |
24927 |
7 |
99.98 |
0.03 |
| [894.11 - 922.05) |
908.08 |
5 |
0.02 |
24932 |
6 |
100 |
0.02 |
| [922.05 - 949.99] |
936.02 |
1 |
0.00 |
24933 |
1 |
100 |
0 |
| Totales |
- |
24933 |
100.00 |
- |
- |
- |
- |
| Autor: Grupo 2
Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india |
# 1. CARGA DE PAQUETES Y DATOS (Replicado para integridad)
# ==============================================================================
# Cargar librerías necesarias
library(gt)
library(dplyr)
# Carga de datos
datos <- read.csv("~/ariana tercer semestre/Estadistica/city_day.csv",
header = TRUE,
sep = ",",
dec = ".")
# ==============================================================================
# 2. PREPARACIÓN Y LIMPIEZA DE DATOS DE MATERIA PARTICULADA PM2.5 (Replicado para integridad)
# ==============================================================================
# Extracción de los "-" (valores inexistentes) de la variable PM2.5
pm25 <- datos$PM2.5[datos$PM2.5 != "-"]
# Conversión a numérico
pm25 <- as.numeric(pm25)
# Redondeo para cálculos de intervalos precisos
pm25 <- round(pm25, 3)
# Definir N (Tamaño muestral)
N <- length(pm25)
min_pm25 <- min(pm25)
max_pm25 <- max(pm25)
# ==============================================================================
# 5. CÁLCULOS PARA LA DISTRIBUCIÓN SIMPLIFICADA (13 CLASES)
# ==============================================================================
# Se utiliza la función hist() para obtener los intervalos simplificados
Histograma_pm25 <- hist(pm25, breaks = 13, plot = FALSE) # No mostrar la gráfica aún
# Extraer elementos simplificados
Lis <- Histograma_pm25$breaks[1:(length(Histograma_pm25$breaks) - 1)]
Lss <- Histograma_pm25$breaks[2:length(Histograma_pm25$breaks)]
MCs <- (Lis + Lss) / 2
nis <- Histograma_pm25$counts
# Frecuencias relativas y acumuladas simplificadas
his <- (nis / N) * 100
Nis_asc <- cumsum(nis)
His_asc <- cumsum(his)
Nis_desc <- rev(cumsum(rev(nis)))
His_desc <- rev(cumsum(rev(his)))
# Crear el Data Frame Simplificado
TDF_pm25simplificado <- data.frame(
Intervalo = paste0("[", round(Lis, 2), " - ", round(Lss, 2), ")"),
MC = round(MCs, 2),
ni = nis,
hi = round(his, 2),
Ni_asc = Nis_asc,
Hi_asc = round(His_asc, 2),
Ni_desc = Nis_desc,
Hi_desc = round(His_desc, 2)
)
# Renombrar columnas con los nombres finales (usando comillas invertidas para % en R)
colnames(TDF_pm25simplificado) <- c("Intervalo", "MC", "ni", "hi(%)",
"Ni_asc", "Hi_asc (%)", "Ni_desc", "Hi_desc (%)")
# Agregar la fila de totales (Usando nombres temporales para compatibilidad)
totaless <- data.frame(
Intervalo = "Totales",
MC = "-",
ni = sum(nis),
hi = sum(his),
Ni_asc = "-",
Hi_asc = "-",
Ni_desc = "-",
Hi_desc = "-"
)
# Asegurar que las columnas de totaless coincidan con los nombres finales
colnames(totaless) <- colnames(TDF_pm25simplificado)
# Unir los data frames
TDF_pm25simplificado_completa <- rbind(TDF_pm25simplificado, totaless)
# ==============================================================================
# 6. TABLA DE FRECUENCIAS SIMPLIFICADA (Tabla Nro. 2)
# ==============================================================================
TDF_pm25simplificado_completa %>%
gt() %>%
tab_header(
title = "Tabla Nro. 2",
# *** Título actualizado a PM2.5 ***
subtitle = "Distribución de frecuencia simplificada de concentración de Materia Particulada (PM2.5), estudio calidad del aire en India entre 2015-2020"
) %>%
tab_source_note(
source_note = "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 |
| Distribución de frecuencia simplificada de concentración de Materia Particulada (PM2.5), estudio calidad del aire en India entre 2015-2020 |
| Intervalo |
MC |
ni |
hi(%) |
Ni_asc |
Hi_asc (%) |
Ni_desc |
Hi_desc (%) |
| [0 - 100) |
50 |
20516 |
82.28 |
20516 |
82.28 |
24933 |
100 |
| [100 - 200) |
150 |
3281 |
13.16 |
23797 |
95.44 |
4417 |
17.72 |
| [200 - 300) |
250 |
843 |
3.38 |
24640 |
98.82 |
1136 |
4.56 |
| [300 - 400) |
350 |
193 |
0.77 |
24833 |
99.6 |
293 |
1.18 |
| [400 - 500) |
450 |
63 |
0.25 |
24896 |
99.85 |
100 |
0.4 |
| [500 - 600) |
550 |
18 |
0.07 |
24914 |
99.92 |
37 |
0.15 |
| [600 - 700) |
650 |
6 |
0.02 |
24920 |
99.95 |
19 |
0.08 |
| [700 - 800) |
750 |
2 |
0.01 |
24922 |
99.96 |
13 |
0.05 |
| [800 - 900) |
850 |
6 |
0.02 |
24928 |
99.98 |
11 |
0.04 |
| [900 - 1000) |
950 |
5 |
0.02 |
24933 |
100 |
5 |
0.02 |
| Totales |
- |
24933 |
100.00 |
- |
- |
- |
- |
| Autor: Grupo 2
Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india |
# Gráfica N°1
# ------------------------------------------------------------------------------
# Para esta gráfica, usaremos el 'hi(%)' de la tabla simplificada.
n <- as.numeric(nrow(TDF_pm25simplificado))
porcentajes <- TDF_pm25simplificado$`hi(%)`[1:(n-1)]
marcas_clase <- TDF_pm25simplificado$MC[1:(n-1)]
post <- barplot(porcentajes,
space = 0,
col = "skyblue",
# *** Título actualizado a PM2.5 ***
main = "Gr\u00E1fica N\u00B03: Distribuci\u00F3n Porcentual Global de PM2.5
Estudio Calidad del Aire en India, 2015-2020",
# *** Etiqueta del eje X actualizada a PM2.5 ***
xlab = "PM2.5 (\u00B5g/m\u00B3)",
ylab = "Porcentaje (%)",
# Fijamos el límite Y entre 0 y 100
ylim = c(0, 100),
cex.main = 0.9,
cex.lab = 1,
xaxt = "n",
yaxt = "n")
# Dibujamos las etiquetas del Eje X (Marca de Clase)
axis(side = 1,
at = post,
labels = marcas_clase,
tck = -0.02,
las = 2,
cex.axis = 0.6)
# Dibujamos las marcas del Eje Y
axis(side = 2,
at = seq(0, 100, by = 20),
las = 1,
cex.axis = 0.9)

# 4. CONJETURA
# Se conjetura que la concentración de PM2.5 sigue un modelo de probabilidad exponencial,
# ya que la variable en su histograma muestra que la mayor parte de los datos está concentrada
# en el extremo izquierdo (bajos valores de PM2.5) y la frecuencia disminuye rápidamente
# conforme aumentan los valores de PM2.5.
# 5. CÁLCULO DE PARÁMETROS DISTRIBUCIÓN EXPONENCIAL
# Media
media <- mean(pm25)
media
## [1] 67.45058
# Lambda
lambda <- 1/media
lambda
## [1] 0.01482567
# 6. HISTOGRAMA densidad de probabilidad
breaks <- Histograma_pm25$breaks # usamos los intervalos que ya calculaste antes
Histograma_pm25_exp <- hist(pm25,
breaks = breaks,
freq = FALSE,
main = "Gráfica Nº2: Comparación modelo exponencial realidad concentración\n de PM2.5 en estudio calidad de aire India 2015-2020",
xlab = "PM2.5 (µg/m3)",
ylab = "Densidad probabilidad ",
col = "grey", ylim = c(0,0.01), xaxt = "n"
)
axis(1, at = breaks)
# Curva exponencial
curve(dexp(x, rate = lambda),
from = 0, to = max(pm25),
col = "orange", lwd = 2, add = TRUE)

# ========================================================
# 7. TEST DE BONDAD
# Test de Pearson
# ========================================================
# Frecuencias observadas por intervalo
fo <- hist(pm25, breaks = breaks, plot = FALSE)$counts
fo
## [1] 20516 3281 843 193 63 18 6 2 6 5
n <- length(pm25)
# Probabilidades teóricas por intervalo (modelo exponencial)
p <- diff(pexp(breaks, rate = lambda))
p
## [1] 7.729459e-01 1.755005e-01 3.984811e-02 9.047678e-03 2.054312e-03
## [6] 4.664400e-04 1.059071e-04 2.404664e-05 5.459889e-06 1.239690e-06
# Frecuencias esperadas (Fe)
fe <- p * n
fe
## [1] 1.927186e+04 4.375755e+03 9.935330e+02 2.255857e+02 5.122017e+01
## [6] 1.162975e+01 2.640582e+00 5.995550e-01 1.361314e-01 3.090919e-02
# Correlación
Correlación <- cor(fo, fe) * 100
Correlación
## [1] 99.77409
# ========================================================
# Test Chi-cuadrado
# ========================================================
# Fo y Fe en porcentual
Fo_porcentual <- fo / n * 100
Fo_porcentual
## [1] 82.284522520 13.159266835 3.381061244 0.774074520 0.252677175
## [6] 0.072193479 0.024064493 0.008021498 0.024064493 0.020053744
Fe_porcentual <- p * 100
Fe_porcentual
## [1] 7.729459e+01 1.755005e+01 3.984811e+00 9.047678e-01 2.054312e-01
## [6] 4.664400e-02 1.059071e-02 2.404664e-03 5.459889e-04 1.239690e-04
x2 <- sum((Fo_porcentual - Fe_porcentual)^2 / Fe_porcentual)
x2
## [1] 5.803183
k <- length(Fo_porcentual)
grados_libertad <- k - 1
grados_libertad
## [1] 9
umbral_aceptacion <- qchisq(0.95, df = grados_libertad)
umbral_aceptacion
## [1] 16.91898
x2 < umbral_aceptacion
## [1] TRUE
# ========================================================
# 8. CÁLCULO DE PROBABILIDAD
# ¿Cuál es la probabilidad de que la concentración de PM2.5 supere 40 µg/m³?
# ========================================================
1 - pexp(40, rate = lambda)
## [1] 0.552652
# ========================================================
# DEMOSTRACIÓN GRÁFICA DE LA PROBABILIDAD
# ========================================================
# Rango de x para la curva
x <- seq(0, max(pm25), by = 0.001)
y <- dexp(x, rate = lambda)
# Calcular máximo para ajustar ylim
ylim_max <- max(y) * 1.1
# Graficar curva principal
plot(x, y, type = "l", col = "orange", lwd = 2,
xlim = c(0, max(pm25)), ylim = c(0, ylim_max),
main = "Gráfica N°3: Cálculo de probabilidad",
ylab = "Densidad de probabilidad",
xlab = "PM2.5 (µg/m3)", xaxt = "n")
# Área a sombrear (x >= 40)
x_section <- seq(40, max(pm25), by = 0.001)
y_section <- dexp(x_section, rate = lambda)
# Sombrear el área
polygon(c(x_section, rev(x_section)),
c(y_section, rep(0, length(y_section))),
col = rgb(0, 1, 0, 0.5), border = NA)
# Dibujar línea verde sobre el área
lines(x_section, y_section, col = "green", lwd = 2)
# Leyenda
legend("topright", legend = c("Modelo", "Área de Probabilidad"),
col = c("orange", "green"), lwd = 2, lty = c(1, 1))
# Eje x
axis(1, at = seq(0, max(pm25), by = 50))

# ========================================================
# 9. INTERVALO DE CONFIANZA
# ========================================================
media <- mean(pm25)
sigma <- sd(pm25)
n <- length(pm25)
error <- 2 * (sigma / sqrt(n))
# Límites del intervalo de confianza
limite_inferior <- round(media - error, 2)
limite_superior <- round(media + error, 2)
# Crear tabla con intervalo (usando tus valores calculados)
tabla_intervalo <- data.frame(
Intervalo = paste0("P [", limite_inferior, " < µ < ", limite_superior, "] = 95%")
)
tabla_intervalo %>%
gt() %>%
tab_header(
title = md("*Tabla Nro. 3*"),
subtitle = md("**Intervalo de confianza de la concentración de PM2.5, 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"
)