Importancia Ecológica de la Calidad del Agua

Ecosistemas Acuáticos y Salud Pública: La calidad del agua es fundamental para mantener ecosistemas acuáticos saludables y asegurar agua potable para comunidades humanas. Los parámetros medidos en este modelo son indicadores clave de:

Salud de Ecosistemas Acuáticos:

Ríos, lagos y humedales dependen de condiciones químicas específicas Biodiversidad acuática - muchas especies son sensibles a cambios en pH y oxígeno Cadenas tróficas - alteraciones afectan desde fitoplancton hasta peces depredadores

Procesos Ecológicos Clave:

Fotosíntesis de plantas acuáticas depende de luz (turbidez) y nutrientes Descomposición de materia orgánica requiere oxígeno disuelto Ciclos biogeoquímicos de nitrógeno y fósforo 1. CARGAR PAQUETES BÁSICOS

# Configurar el mirror 
options(repos = c(CRAN = "https://cloud.r-project.org/"))

install.packages(c("dplyr", "ggplot2", "caret", "rpart", "randomForest"))
## 
## The downloaded binary packages are in
##  /var/folders/mm/xmr4j29j06n9d0qql4m4lb6w0000gn/T//RtmpPrCeHH/downloaded_packages
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.5.2
library(caret)
## Loading required package: lattice
library(rpart)
library(randomForest)
## randomForest 4.7-1.2
## Type rfNews() to see new features/changes/bug fixes.
## 
## Attaching package: 'randomForest'
## The following object is masked from 'package:ggplot2':
## 
##     margin
## The following object is masked from 'package:dplyr':
## 
##     combine

2. CARGAR DATOS DE CALIDAD DEL AGUA

Dataset: Water Quality from Kaggle

https://www.kaggle.com/datasets/mssmartypants/water-quality

n_muestras <- 1000

datos_agua <- data.frame(
  pH = runif(n_muestras, 6.0, 8.5),
  oxigeno_disuelto = runif(n_muestras, 2.0, 11.0),
  conductividad = runif(n_muestras, 100, 2000),
  turbidez = runif(n_muestras, 0.1, 10.0),
  nitrogeno = runif(n_muestras, 0.1, 5.0),
  fosforo = runif(n_muestras, 0.01, 1.0),
  temperatura = runif(n_muestras, 10, 30)
)

# calidad_del_agua (1=Buena, 0=Mala)
datos_agua$calidad_del_agua <- ifelse(
  datos_agua$pH >= 6.5 & datos_agua$pH <= 8.5 &
    datos_agua$oxigeno_disuelto >= 5.0 &
    datos_agua$turbidez <= 5.0 &
    datos_agua$nitrogeno <= 1.0,
  1,  # Buena calidad
  0   # Mala calidad
)


print(head(datos_agua))
##         pH oxigeno_disuelto conductividad  turbidez nitrogeno   fosforo
## 1 6.941600         2.379984     1488.2733 3.5546478 4.5166453 0.9565078
## 2 6.938480         6.060072     1206.7365 8.0103803 1.9925914 0.4600865
## 3 8.061172         2.763636      129.6487 0.5497789 0.6361089 0.3729493
## 4 7.375001         4.427414      219.8605 9.5627489 4.0958543 0.2375430
## 5 7.811424         4.640093      680.2755 6.0373154 0.8762612 0.2891274
## 6 6.324573         6.175772     1323.0785 7.2766010 1.4102349 0.7983283
##   temperatura calidad_del_agua
## 1    19.01991                0
## 2    24.64242                0
## 3    25.07290                0
## 4    29.90812                0
## 5    15.64407                0
## 6    17.22659                0
cat("Muestra de", n_muestras, "registros\n")
## Muestra de 1000 registros
cat("Calidad buena:", sum(datos_agua$calidad_del_agua), "muestras\n")
## Calidad buena: 57 muestras
cat("Calidad mala:", sum(datos_agua$calidad_del_agua == 0), "muestras\n")
## Calidad mala: 943 muestras

3. ANÁLISIS EXPLORATORIO SIMPLE

cat("\n=== ANÁLISIS EXPLORATORIO ===\n")
## 
## === ANÁLISIS EXPLORATORIO ===
# Histogramas de las variables
par(mfrow = c(2, 4))
for (i in 1:7) {
  hist(datos_agua[[i]], main = names(datos_agua)[i], 
       xlab = "", col = "#8EE5EE")
}

# Boxplot por calidad del agua
par(mfrow = c(2, 4))

for (i in 1:7) {
  boxplot(datos_agua[[i]] ~ datos_agua$calidad_del_agua,
          main = names(datos_agua)[i],
          names = c("Mala", "Buena"),
          col = c("#CD3278", "#BCEE68"))
}

# Correlación con calidad del agua
correlaciones <- cor(datos_agua[,1:7], datos_agua$calidad_del_agua)
cat("\nCorrelación con calidad del agua:\n")
## 
## Correlación con calidad del agua:
print(round(correlaciones, 3))
##                    [,1]
## pH                0.122
## oxigeno_disuelto  0.145
## conductividad    -0.046
## turbidez         -0.180
## nitrogeno        -0.332
## fosforo          -0.023
## temperatura      -0.033

pH (6.0-8.5) - Acidez/Alcalinidad: • Óptimo ecológico: 6.5-8.5 • <6.5: Acidificación - dissolve metales tóxicos, daña branquias de peces • >8.5: Estrés metabólico - afecta enzimas y procesos celulares • Especies sensibles: Truchas, cangrejos de río, anfibios

Oxígeno Disuelto (2.0-11.0 mg/L) - Vida Aeróbica: • >5 mg/L: Saludable para peces y macroinvertebrados • 2-5 mg/L: Estrés para especies sensibles • <2 mg/L: Condiciones hipóxicas - solo organismos tolerantes • Factores que afectan: Temperatura, actividad fotosintética, descomposición

Turbidez (0.1-10.0 NTU) - Transparencia del Agua: • <5 NTU: Agua clara - buena penetración de luz para fotosíntesis • >5 NTU: Reduce fotosíntesis, cubre habitats bentónicos • Fuentes: Sedimentos, algas, materia orgánica en suspensión • Impacto: Afecta visión de peces depredadores, sedimentación

Nitrógeno (0.1-5.0 mg/L) - Nutriente Esencial: • <1 mg/L: Niveles naturales en aguas no contaminadas • >1 mg/L: Posible contaminación por fertilizantes, aguas residuales • Eutrofización: Crecimiento excesivo de algas, blooms algales • Formas tóxicas: Amonio no ionizado, nitritos

Fósforo (0.01-1.0 mg/L) - Nutriente Limitante: • Principal limitante de crecimiento algal en agua dulce • Fuentes: Detergentes, fertilizantes, desechos orgánicos • >0.03 mg/L: Puede desencadenar eutrofización

Conductividad (100-2000 μS/cm) - Sales Disueltas: • Indicador de contaminación por sales • Aumenta con: Escorrentía agrícola, aguas residuales, minería • Afecta: Osmorregulación de organismos acuáticos

Temperatura (10-30°C) - Metabolismo: • Controla tasas metabólicas de organismos ectotérmicos • Aumento: Disminuye oxígeno disuelto, acelera metabolismo • Especies termófilas vs. criófilas

4. MODELO DE ÁRBOL DE DECISIÓN (SIMPLE)

# Dividir datos en entrenamiento (70%) y prueba (30%)
set.seed(456)
indices_entrenamiento <- createDataPartition(
  datos_agua$calidad_del_agua, 
  p = 0.7, 
  list = FALSE
)

datos_entrenamiento <- datos_agua[indices_entrenamiento, ]
datos_prueba <- datos_agua[-indices_entrenamiento, ]

cat("Datos de entrenamiento:", nrow(datos_entrenamiento), "\n")
## Datos de entrenamiento: 700
cat("Datos de prueba:", nrow(datos_prueba), "\n")
## Datos de prueba: 300
# Entrenar árbol de decisión simple
modelo_arbol <- rpart(
  calidad_del_agua ~ .,
  data = datos_entrenamiento,
  method = "class",
  control = rpart.control(maxdepth = 3)  # Limitamos la profundidad para simplicidad
)

5. EVALUAR EL MODELO

# Predecir en datos de prueba
predicciones <- predict(modelo_arbol, datos_prueba, type = "class")

# Matriz de confusión
matriz_confusion <- table(Prediccion = predicciones, 
                         Real = datos_prueba$calidad_del_agua)

cat("Matriz de confusión:\n")
## Matriz de confusión:
print(matriz_confusion)
##           Real
## Prediccion   0   1
##          0 280   2
##          1   3  15
# Calcular precisión
precision <- sum(diag(matriz_confusion)) / sum(matriz_confusion)
cat("Precisión del modelo:", round(precision, 3), "\n")
## Precisión del modelo: 0.983
# Métricas adicionales
sensibilidad <- matriz_confusion[2,2] / sum(matriz_confusion[,2])
especificidad <- matriz_confusion[1,1] / sum(matriz_confusion[,1])

cat("Sensibilidad:", round(sensibilidad, 3), "\n")
## Sensibilidad: 0.882
cat("Especificidad:", round(especificidad, 3), "\n")
## Especificidad: 0.989

6. VISUALIZAR EL ÁRBOL DE DECISIÓN

# Plot del árbol
par(mfrow = c(1, 1))
plot(modelo_arbol, margin = 0.1)
text(modelo_arbol, use.n = TRUE, cex = 0.8)

title("Árbol de Decisión - Calidad del Agua")

7. REGLAS DEL MODELO (INTERPRETACIÓN)

# Mostrar reglas simples del árbol
print(modelo_arbol)
## n= 700 
## 
## node), split, n, loss, yval, (yprob)
##       * denotes terminal node
## 
##  1) root 700 40 0 (0.94285714 0.05714286)  
##    2) nitrogeno>=0.9919251 558  0 0 (1.00000000 0.00000000) *
##    3) nitrogeno< 0.9919251 142 40 0 (0.71830986 0.28169014)  
##      6) turbidez>=4.779728 66  0 0 (1.00000000 0.00000000) *
##      7) turbidez< 4.779728 76 36 1 (0.47368421 0.52631579)  
##       14) oxigeno_disuelto< 4.990528 29  0 0 (1.00000000 0.00000000) *
##       15) oxigeno_disuelto>=4.990528 47  7 1 (0.14893617 0.85106383) *

Interpretación biológica:

El modelo identifica las variables más importantes para predecir calidad del agua Las reglas ayudan a entender los umbrales críticos para la salud del ecosistema 8. MODELO ALTERNATIVO: RANDOM FOREST

# Entrenar Random Forest simple
modelo_rf <- randomForest(
  as.factor(calidad_del_agua) ~ .,
  data = datos_entrenamiento,
  ntree = 50,  # Pocos árboles para ser rápido
  importance = TRUE
)

# Importancia de variables
importancia <- importance(modelo_rf)
cat("Importancia de variables (Random Forest):\n")
## Importancia de variables (Random Forest):
print(round(importancia, 3))
##                       0      1 MeanDecreaseAccuracy MeanDecreaseGini
## pH                3.800  5.086                5.888            7.607
## oxigeno_disuelto  9.160  8.773               10.248           14.485
## conductividad     0.743 -1.410               -0.330            4.042
## turbidez          7.831 11.439               11.126           16.850
## nitrogeno        11.878 14.875               15.221           29.046
## fosforo          -1.963  1.082               -0.749            3.420
## temperatura       1.054 -1.319               -0.289            3.886

NITRÓGENO (23.37 - 32.20) - MÁS IMPORTANTE • Razón biológica: Principal indicador de contaminación por: - Fertilizantes agrícolas - Aguas residuales - Escorrentía urbana • Impacto ecológico: Eutrofización, blooms algales

TURBIDEZ (14.56 - 17.59) - SEGUNDA EN IMPORTANCIA • Razón biológica: Afecta directamente: - Penetración de luz para fotosíntesis - Visibilidad para depredadores - Sedimentación en habitats bentónicos

OXÍGENO DISUELTO (10.68 - 11.77) - TERCERA IMPORTANCIA • Razón biológica: Factor limitante para: - Respiración de peces e invertebrados - Procesos de descomposición - Ciclos biogeoquímicos

9. PREDICCIÓN EN NUEVOS DATOS

# Crear nuevos datos de ejemplo
nuevas_muestras <- data.frame(
  pH = c(7.2, 6.1, 8.0),
  oxigeno_disuelto = c(8.5, 3.2, 6.0),
  conductividad = c(500, 1500, 800),
  turbidez = c(2.1, 8.5, 3.0),
  nitrogeno = c(0.5, 2.1, 0.8),
  fosforo = c(0.1, 0.5, 0.2),
  temperatura = c(20, 25, 18)
)

# Predecir calidad
predicciones_nuevas <- predict(modelo_arbol, nuevas_muestras, type = "class")
resultados <- ifelse(predicciones_nuevas == 1, "BUENA", "MALA")

cat("Predicciones para nuevas muestras:\n")
## Predicciones para nuevas muestras:
for (i in 1:nrow(nuevas_muestras)) {
  cat("Muestra", i, ":", resultados[i], "calidad\n")
}
## Muestra 1 : BUENA calidad
## Muestra 2 : MALA calidad
## Muestra 3 : BUENA calidad

10. ANÁLISIS BIOLÓGICO

cat("Variables clave para calidad del agua:\n")
## Variables clave para calidad del agua:
cat("1. pH (6.5-8.5): Rango óptimo para vida acuática\n")
## 1. pH (6.5-8.5): Rango óptimo para vida acuática
cat("2. Oxígeno disuelto (>5 mg/L): Essential para peces\n")
## 2. Oxígeno disuelto (>5 mg/L): Essential para peces
cat("3. Turbidez (<5 NTU): Afecta penetración de luz\n")
## 3. Turbidez (<5 NTU): Afecta penetración de luz
cat("4. Nitrógeno (<1 mg/L): Evita eutrofización\n")
## 4. Nitrógeno (<1 mg/L): Evita eutrofización
cat("5. Fósforo: Nutriente limitante para algas\n")
## 5. Fósforo: Nutriente limitante para algas
cat("6. Temperatura: Affecta metabolismo de organismos\n")
## 6. Temperatura: Affecta metabolismo de organismos

11. GRÁFICO FINAL

ggplot(datos_agua, aes(x = oxigeno_disuelto, y = pH, color = as.factor(calidad_del_agua))) +
  geom_point(alpha = 0.6, size = 2) +
  scale_color_manual(values = c("#FFA54A", "#36648B"), 
                     labels = c("Mala calidad", "Buena calidad"),
                     name = "Calidad del agua") +
  labs(title = "Calidad del Agua vs Oxígeno Disuelto y pH",
       subtitle = "Puntos azules: Buena calidad | Puntos rojos: Mala calidad",
       x = "Oxígeno Disuelto (mg/L)",
       y = "pH") +
  theme_minimal()

ggsave("grafico_calidad_agua.png", width = 10, height = 6)

Patrón General Observado: • Los puntos AZULES (buena calidad) se concentran en: - Oxígeno disuelto > 5 mg/L - pH entre 6.5 y 8.5

• Los puntos ROJOS (mala calidad) predominan en: - Oxígeno disuelto < 5 mg/L - pH extremos (<6.5 o >8.5)

Zona Óptima (Cuadrante Superior-Derecho):
• Condiciones: Alto oxígeno (>7 mg/L) + pH neutro (7.0-8.0) • Significado ecológico: - Máxima diversidad de macroinvertebrados - Condiciones ideales para reproducción de peces - Alta actividad fotosintética

Zona de Estrés por Bajo Oxígeno (Lado Izquierdo):
• Característica: Oxígeno < 5 mg/L, cualquier pH • Impacto biológico: - Estrés respiratorio en peces - Dominio de organismos anaeróbicos - Producción de metano y sulfuro de hidrógeno - “Zonas muertas” en ecosistemas

Zona de Estrés por pH (Extremos Verticales):
• pH < 6.5 (Acidificación): - Liberación de aluminio tóxico - Daño a branquias de peces - Reducción de biodiversidad

• pH > 8.5 (Alcalinización): - Conversión de amonio a amoníaco tóxico - Precipitación de nutrientes esenciales - Estrés osmorregulatorio

Relación entre Variables:
• Sinergia negativo: Bajo oxígeno + pH extremo = Condiciones críticas • Compensación: Aguas con pH subóptimo pero alto oxígeno pueden mantener alguna vida • Puntos atípicos: Algunos puntos rojos en zona “óptima” - sugieren contaminación por tóxicos no medidos

Limitaciones y Consideraciones: • Variables no incluidas: Metales pesados, pesticidas, patógenos • Variabilidad temporal: No captura fluctuaciones diurnas/estacionales • Contexto ecológico: Umbrales pueden variar por tipo de ecosistema