1.Carga de datos

# Librerías
library(kableExtra)
library(knitr)
library(magrittr)
library(dplyr)
## 
## Adjuntando el paquete: 'dplyr'
## The following object is masked from 'package:kableExtra':
## 
##     group_rows
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(e1071)

# Cargar datos
datos <- read.csv("china_water_pollution_data.csv",
                  header = TRUE,
                  sep = ",",
                  dec = ".")
Nitrito <- datos$Nitrite_mg_L

2. Extracción de la variable

Nitrito <- na.omit(Nitrito)
Nitrito <- Nitrito[Nitrito >= 0]

n <- length(Nitrito)
n
## [1] 2941

3. Tabla de distribución de frecuencia

3.1 Construcción manual (Regla de Sturges)

# 1. Asegurar que Nitrito sea un vector limpio y numérico
Nitrito <- as.numeric(na.omit(datos$Nitrite_mg_L))
Nitrito <- Nitrito[Nitrito >= 0]
n_total <- length(Nitrito) # Esto debe ser 3000

# 2. Definir parámetros
minimo <- min(Nitrito)
maximo <- max(Nitrito)
K <- floor(1 + 3.322 * log10(n_total))

# 3. EL TRUCO DEFINITIVO PARA LOS 3000:
# Creamos los cortes pero expandimos los extremos 
# para que el mínimo y el máximo REALES queden adentro del rango.
rango_ajustado <- seq(from = minimo - 0.001, to = maximo + 0.001, length.out = K + 1)

# 4. Generar la tabla de frecuencias
# 'include.lowest = TRUE' es vital para que el primer dato entre
intervalos <- cut(Nitrito, breaks = rango_ajustado, include.lowest = TRUE, right = TRUE)
tabla_base <- table(intervalos)
ni <- as.numeric(tabla_base)

# 5. Verificación de seguridad (Si falta algo, se suma a la última clase)
if(sum(ni) != n_total){
  diferencia <- n_total - sum(ni)
  ni[length(ni)] <- ni[length(ni)] + diferencia
}

# 6. Construcción de la tabla final
Li <- rango_ajustado[-length(rango_ajustado)]
Ls <- rango_ajustado[-1]
Mc <- (Li + Ls)/2
hi <- (ni / sum(ni)) * 100
Ni_asc <- cumsum(ni)
Hi_asc <- cumsum(hi)

TDF_Nitrito <- data.frame(
  Lim_inf = Li,
  Lim_sup = Ls,
  MC = Mc,
  ni = ni,
  hi = hi,
  Ni_asc = Ni_asc,
  Hi_asc = Hi_asc
)

# 7. Mostrar con kable
library(knitr)
library(kableExtra)

kable(TDF_Nitrito, 
      digits = 3, 
      align = "c",
      col.names = c("Lím. Inf.", "Lím. Sup.", "MC", "ni", "hi (%)", "Ni Asc.", "Hi Asc. (%)"),
      caption = paste("TABLA FINAL - TOTAL DATOS:", sum(ni))) %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
TABLA FINAL - TOTAL DATOS: 2941
Lím. Inf. Lím. Sup. MC ni hi (%) Ni Asc. Hi Asc. (%)
-0.001 0.004 0.001 87 2.958 87 2.958
0.004 0.008 0.006 246 8.365 333 11.323
0.008 0.013 0.010 286 9.725 619 21.047
0.013 0.017 0.015 515 17.511 1134 38.558
0.017 0.022 0.020 489 16.627 1623 55.185
0.022 0.026 0.024 560 19.041 2183 74.226
0.026 0.031 0.029 383 13.023 2566 87.249
0.031 0.036 0.033 205 6.970 2771 94.220
0.036 0.040 0.038 113 3.842 2884 98.062
0.040 0.045 0.043 38 1.292 2922 99.354
0.045 0.049 0.047 15 0.510 2937 99.864
0.049 0.054 0.052 4 0.136 2941 100.000

3.2. Simplificación

La tabla de distribución de frecuencias del Nitrito fue construida inicialmente aplicando la Regla de Sturges para determinar el número óptimo de clases.

Posteriormente, el procedimiento se simplificó utilizando la función hist(), obteniendo automáticamente los intervalos y frecuencias, confirmando los resultados obtenidos manualmente.

Hist_Nitrito <- hist(Nitrito,
                     breaks = K,
                     plot = FALSE)

Li <- Hist_Nitrito$breaks[-length(Hist_Nitrito$breaks)]
Ls <- Hist_Nitrito$breaks[-1]
ni <- Hist_Nitrito$counts
hi <- round((ni/sum(ni))*100,2)

TDF_simplificada <- data.frame(
  Lim_inf = round(Li,2),
  Lim_sup = round(Ls,2),
  ni = ni,
  hi = hi
)

kable(TDF_simplificada,
      align="c",
      caption="Tabla simplificada obtenida mediante hist()")
Tabla simplificada obtenida mediante hist()
Lim_inf Lim_sup ni hi
0.00 0.00 173 5.88
0.00 0.01 285 9.69
0.01 0.01 461 15.67
0.01 0.02 586 19.93
0.02 0.03 566 19.25
0.03 0.03 428 14.55
0.03 0.04 272 9.25
0.04 0.04 113 3.84
0.04 0.04 44 1.50
0.04 0.05 10 0.34
0.05 0.06 3 0.10

4. Gráficas

4.1 Histograma

hist(Nitrito, breaks = 10,
     main = "Gráfica N°1: Distribución del Nitrito
     en el estudio de contaminación del agua
     en China en el año 2023",
     xlab = "Nitrito (mg/L)",
     ylab = "Cantidad",
     ylim = c(0, max(ni)),
     col = "lightgreen")

4.2 Histograma general

hist(Nitrito, breaks = 10,
     main = "Gráfica N°2: Distribución general del Nitrito
     en el estudio de contaminación del agua en China 2023",
     xlab = "Nitrito (mg/L)",
     ylab = "Cantidad",
     ylim = c(0, max(ni)),
     col = "lightgreen")

4.3 Histograma Porcentual General

barplot(
  height = TDF_Nitrito$hi, 
  space = 0,
  col = "skyblue",
  main = "Gráfica N°3: Distribución porcentual del Nitrito\nen el estudio de contaminación del agua en China 2023",
  xlab = "Nitrito (mg/L)",
  ylab = "Porcentaje (%)",
  names.arg = TDF_Nitrito$MC,
  ylim = c(0, max(TDF_Nitrito$hi) + 10) # Ajuste automático del eje Y
)

5. Diagrama de Caja

boxplot(Nitrito,
        horizontal = TRUE,
        main = "Gráfica N°6: Diagrama de caja del Nitrito
        en el estudio de contaminación del agua en China 2023",
        xlab = "Nitrito (mg/L)",
        col = "green",
        outline = TRUE)

summary(Nitrito)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.00000 0.01400 0.02000 0.02043 0.02700 0.05300

6. Ojivas

6.1 Ojivas Ascendentes y Descendentes (ni)

Ni_asc <- cumsum(ni)
Ni_desc <- rev(cumsum(rev(ni)))

plot(Ls, Ni_asc,
     type = "o",
     col = "orange",
     lwd = 3,
     xlab = "Nitrito (mg/L)",
     ylab = "Frecuencia acumulada",
     main = "Gráfica N°7: Ojiva Ascendente y Descendente")

lines(Li, Ni_desc,
      type = "o",
      col = "green",
      lwd = 3)

6.2 Ojivas Ascendentes y Descendentes (hi)

Hi_asc <- cumsum(hi)
Hi_desc <- rev(cumsum(rev(hi)))

plot(Ls, Hi_asc,
     type = "o",
     col = "blue",
     lwd = 3,
     xlab = "Nitrito (mg/L)",
     ylab = "Porcentaje acumulado (%)",
     main = "Gráfica N°8: Ojiva porcentual Ascendente y Descendente")

lines(Li, Hi_desc,
      type = "o",
      col = "red",
      lwd = 3)

7. Indicadores Estadísticos

7.1 Indicadores de Tendencia Central

media <- round(mean(Nitrito),2)
mediana <- median(Nitrito)

max_ni <- max(TDF_Nitrito$ni)
moda <- TDF_Nitrito$MC[TDF_Nitrito$ni == max_ni]

media
## [1] 0.02
mediana
## [1] 0.02
moda
## [1] 0.02420833

7.2 Indicadores de Dispersión

varianza <- var(Nitrito)
sd <- sd(Nitrito)
cv <- round((sd/media)*100,2)

varianza
## [1] 8.89307e-05
sd
## [1] 0.009430307
cv
## [1] 47.15

7.3 Indicadores de Forma

library(e1071)

asimetria <- skewness(Nitrito, type = 2)
curtosis <- kurtosis(Nitrito)

asimetria
## [1] 0.1695714
curtosis
## [1] -0.2827326

8. Tabla de Resumen

tabla_indicadores <- data.frame(
  "Variable" = "Nitrito (mg/L)",
  "Rango" = paste0("[",min(Nitrito),";",max(Nitrito),"]"),
  "X" = media,
  "Me" = round(mediana,2),
  "Mo" = moda,
  "V" = round(varianza,2),
  "Sd" = round(sd,2),
  "Cv" = cv,
  "As" = round(asimetria,2),
  "K" = round(curtosis,2)
)

kable(tabla_indicadores, align='c',
      caption="Conclusiones de la variable Nitrito (mg/L)")
Conclusiones de la variable Nitrito (mg/L)
Variable Rango X Me Mo V Sd Cv As K
Nitrito (mg/L) [0;0.053] 0.02 0.02 0.0242083 0 0.01 47.15 0.17 -0.28

9. Conclusión

La variable Nitrito (mg/L) fluctúa entre 0 y 0.053 mg/L, y sus valores giran en torno a 0.02 mg/L, con una desviación estándar de 0.01 mg/L, siendo un conjunto de datos con variabilidad relativamente alta (CV = 47.15%). Los valores se distribuyen de manera ligeramente asimétrica (As ≈ 0.17), indicando que hay una leve concentración hacia valores más altos, y presentan una curtosis negativa (K = -0.28), evidenciando una distribución algo más plana que la normal. Por lo anterior, el comportamiento de la variable Nitrito (mg/L) puede considerarse estable y dentro de rangos adecuados para el análisis de la calidad del agua en China durante el año 2023.