# -------------------------
# Cargar librerías
# -------------------------
library(gt)
library(dplyr)
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
# -------------------------
# Cargar datos
# -------------------------
datos <- read.csv("waterPollution.csv",
sep = ",",
stringsAsFactors = FALSE)
# ================================
# SELECCIÓN Y SEPARACIÓN
# ================================
datos$resultMeanValue <- as.numeric(gsub("-", NA, datos$resultMeanValue))
fosforo <- datos %>%
filter(observedPropertyDeterminandCode == "CAS_7723-14-0") %>%
select(waterBodyIdentifier, phenomenonTimeReferenceYear, X_val = resultMeanValue)
nitratos <- datos %>%
filter(observedPropertyDeterminandCode == "CAS_14797-55-8") %>%
select(waterBodyIdentifier, phenomenonTimeReferenceYear, Y_val = resultMeanValue)
datos_pareados <- inner_join(fosforo, nitratos, by = c("waterBodyIdentifier", "phenomenonTimeReferenceYear"))
## Warning in inner_join(fosforo, nitratos, by = c("waterBodyIdentifier", "phenomenonTimeReferenceYear")): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 28 of `x` matches multiple rows in `y`.
## ℹ Row 64 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
## "many-to-many"` to silence this warning.
datos_pareados <- datos_pareados[complete.cases(datos_pareados$X_val, datos_pareados$Y_val), ]
# ------------------------------------------------------------------------------
# 4. IQR PARA ATÍPICOS
# ------------------------------------------------------------------------------
if (nrow(datos_pareados) > 10) {
# IQR para Fósforo (X)
Q1_X <- quantile(datos_pareados$X_val, 0.25)
Q3_X <- quantile(datos_pareados$X_val, 0.75)
IQR_X <- Q3_X - Q1_X
# IQR para Nitratos (Y)
Q1_Y <- quantile(datos_pareados$Y_val, 0.25)
Q3_Y <- quantile(datos_pareados$Y_val, 0.75)
IQR_Y <- Q3_Y - Q1_Y
# Aplicar filtro
datos_filtrados <- datos_pareados[
datos_pareados$X_val >= (Q1_X - 1.5 * IQR_X) & datos_pareados$X_val <= (Q3_X + 1.5 * IQR_X) &
datos_pareados$Y_val >= (Q1_Y - 1.5 * IQR_Y) & datos_pareados$Y_val <= (Q3_Y + 1.5 * IQR_Y),
]
if(nrow(datos_filtrados) == 0) datos_filtrados <- datos_pareados
} else {
stop("No hay suficientes muestras emparejadas en el mismo año/lugar para estos compuestos.")
}
# Asignación final de variables limpias
x <- datos_filtrados$X_val
y <- datos_filtrados$Y_val
# Tabla de Pares de Valores (TVP)
TVP <- data.frame(Fosforo = x, Nitratos = y)
# ------------------------------------------------------------------------------
# 5. GRÁFICA No1: DIAGRAMA DE DISPERSIÓN
# ------------------------------------------------------------------------------
plot(x, y,
main = "Gráfica No1: Relación entre Fósforo Total y Nitratos en Cuerpos
de Agua de Europa",
xlab = "Fósforo Total (mg/L)",
ylab = "Nitratos (mg/L)",
col = rgb(91, 192, 222, maxColorValue = 255, alpha = 60),
pch = 16,
cex = 0.8,
xlim = c(0, max(x) * 1.05),
ylim = c(0, max(y) * 1.05))
# ------------------------------------------------------------------------------
# 6. CONJETURA
# ------------------------------------------------------------------------------
# La distribución de los puntos sugiere una relación positiva entre ambos nutrientes.
# A medida que los niveles de Fósforo Total aumentan en los cuerpos de agua, los niveles de Nitratos
# también tienden a incrementarse, debido a que comparten fuentes comunes de contaminación antropogénica
# (como escorrentía agrícola, fertilizantes y aguas residuales urbanas).
# Esta tendencia justifica el ajuste de un modelo de regresión lineal para evaluar la coexistencia
# y el comportamiento conjunto de ambos contaminantes en los ecosistemas acuáticos europeos.
# ------------------------------------------------------------------------------
# 6. CÁLCULO DE PARÁMETROS DEL MODELO LINEAL
# ------------------------------------------------------------------------------
regresionlineal <- lm(y ~ x)
# Extraer coeficientes automáticamente
intercepto <- coef(regresionlineal)[1]
pendiente <- coef(regresionlineal)[2]
print(paste("Intercepto (beta_0):", round(intercepto, 4)))
## [1] "Intercepto (beta_0): 5.2799"
print(paste("Pendiente (beta_1):", round(pendiente, 4)))
## [1] "Pendiente (beta_1): 85.0372"
# ------------------------------------------------------------------------------
# 7. GRÁFICA No2: REGRESIÓN LINEAL
# ------------------------------------------------------------------------------
plot(x, y,
main = "Gráfica No2: Regresión lineal entre Fósforo Total y Nitratos
en Cuerpos de Agua de Europa",
xlab = "Fósforo Total (mg/L)",
ylab = "Nitratos (mg/L)",
col = rgb(91, 192, 222, maxColorValue = 255, alpha = 60),
pch = 16,
cex = 0.8,
cex.main = 1,
cex.lab = 1,
cex.axis = 0.9,
xlim = c(0, max(x) * 1.05),
ylim = c(0, max(y) * 1.05),
xaxs = "i",
yaxs = "i")
abline(regresionlineal, col = "red", lwd = 2)
# ================
# TEST DE BONDAD
# ================
# Coeficiente de correlación de Pearson (r)
r_valor <- cor(x, y)
r_porcentaje <- r_valor * 100
# Coeficiente de determinación (R²) basado en el modelo ajustado
r2_porcentaje <- summary(regresionlineal)$r.squared * 100
print(paste("Coeficiente de correlación (r %):", round(r_porcentaje, 2), "%"))
## [1] "Coeficiente de correlación (r %): 47.12 %"
print(paste("Coeficiente de determinación (R² %):", round(r2_porcentaje, 2), "%"))
## [1] "Coeficiente de determinación (R² %): 22.2 %"
# ------------------------------------------------------------------------------
# 10. RESTRICCIONES
# ------------------------------------------------------------------------------
# Dominio [x]: D= {R+^0} (Fósforo Total >= 0)
# Dominio [y]: D= {R+^0} (Nitratos >= 0)
# ¿Existe algún valor en dominio de x que sustituido en el modelo matemático genere un valor en y fuera de su dominio?
# Al igual que con el material particulado, las concentraciones de nutrientes en ecosistemas acuáticos no pueden ser negativas. Físicamente, un valor de Fósforo (x = 0) debería idealmente dar valores de Nitratos (y) mayores o iguales a cero. Si el intercepto (beta_0) del modelo matemático resulta ser ligeramente negativo debido al ajuste estadístico, teóricamente existirían valores muy bajos de x que darían un resultado de y negativo (fuera de su dominio físico). En la práctica, el modelo se restringe y valida únicamente para el rango de concentraciones reales observadas en los cuerpos de agua europeos.
# ------------------------------------------------------------------------------
# 11. APLICACIONES DEL MODELO
# ------------------------------------------------------------------------------
# Evaluación para un valor esperado de Fósforo Total = 0.5 mg/L
Fosforo_evaluar <- 0.5
Nitratos_esperado <- intercepto + (pendiente * Fosforo_evaluar)
print(paste("Nitratos esperados (mg/L) para Fósforo =", Fosforo_evaluar, ":", round(Nitratos_esperado, 4)))
## [1] "Nitratos esperados (mg/L) para Fósforo = 0.5 : 47.7985"
En el estudio de la contaminación del agua en Europa se observa una relación lineal positiva entre la concentración de Fósforo Total y los niveles de Nitratos. El modelo matemático se describe mediante la ecuación y = 5.28x + 85.037. El modelo explica aproximadamente el 22.2% de la variabilidad de los nitratos, lo que indica una asociación moderada entre ambas variables. El porcentaje restante de la variabilidad 77.8% puede atribuirse a otros factores físicos, químicos y biológicos que no fueron considerados, como las corrientes hídricas, la temperatura del agua, el oxígeno disuelto o la presencia de otros vertidos contaminantes. Las restricciones se aplican para todo el dominio natural de la variable: x ≥ 0, y ≥ 0, siendo el modelo más confiable dentro del rango observado de los datos en los ecosistemas acuáticos europeos.