En este trabajo realizaremos un análisis geoestadístico sobre el primer periodo (01/10/2020) de las mediciones de los árboles de aguacate en Cauca. El objetivo principal es interpolar la variable temperatura usando variogramas y kriging (si la variable muestra autocorrelación espacial). Si temperatura no presenta autocorrelación, probaremos con otras variables (humedad relativa, altura, velocidad del viento, etc.). El flujo de trabajo sigue los pasos vistos en clase: EDA, creación de geodato, detección de tendencia, variograma experimental, ajuste de modelos teóricos (exponencial, gaussiano, esférico) y predicción espacial por kriging.
# --- Cargar librerías necesarias ---
if (!require(readxl)) install.packages("readxl")
library(readxl)
if (!require(geoR)) install.packages("geoR")
library(geoR)
if (!require(ggplot2)) install.packages("ggplot2")
library(ggplot2)
ruta <- "C:/Users/angie/OneDrive/ANGIE COLLAZOS/MSESTRIA CIENCIA DE DATOS/SIG/SIG/aguacate/Datos_Completos_Aguacate.xlsx"
datos <- read_excel(ruta)
datos <- as.data.frame(datos)
names(datos)
head(datos, 5)
library(dplyr)
# ajustamos el formato de fecha
datos$FORMATTED_DATE_TIME <- gsub(",", "", datos$FORMATTED_DATE_TIME)
datos$FORMATTED_DATE_TIME <- trimws(datos$FORMATTED_DATE_TIME)
datos$FECHA <- sub(" .*", "", datos$FORMATTED_DATE_TIME)
# formato fecha
datos$FECHA <- as.Date(datos$FECHA, format = "%d/%m/%Y")
unique(datos$FECHA)
## [1] "2019-08-21" "2019-09-04" "2019-09-19" "2019-10-01" "2019-10-18"
## [6] "2019-11-13" "2020-07-16" "2020-07-30" "2020-08-11" "2020-09-30"
## [11] "2020-10-14" "2019-08-14" "2019-08-15" "2019-08-28" "2019-09-12"
## [16] "2019-09-25" "2019-10-09" "2020-07-07" "2020-07-21" "2020-08-06"
## [21] "2020-08-20" "2020-10-01" "2020-07-09" "2020-07-23" "2020-08-03"
## [26] "2020-08-18" "2020-08-26" "2020-09-18" "2020-09-23" "2020-10-05"
## [31] "2019-08-08" "2019-08-27" "2019-09-11" "2019-09-24" "2019-10-08"
## [36] "2019-11-05" "2020-07-14" "2020-07-28" "2020-08-13" "2020-08-27"
## [41] "2020-09-09" "2020-09-22" "2020-10-06" "2020-10-23" "2019-07-30"
## [46] "2019-08-22" "2019-09-03" "2019-09-20" "2019-10-02" "2019-10-16"
# filtramos segun la actividad
datos_2020 <- filter(datos, FECHA == as.Date("2020-10-01"))
# Revisamos cuántos registros quedaron
nrow(datos_2020)
## [1] 534
# Vemos las primeras filas
head(datos_2020, 6)
## id_arbol Latitude Longitude FORMATTED_DATE_TIME
## 1 1 2.393549 -76.71124 01/10/2020 10:11:12 a m
## 2 2 2.393573 -76.71120 01/10/2020 10:11:12 a m
## 3 3 2.393541 -76.71113 01/10/2020 10:11:12 a m
## 4 4 2.393503 -76.71119 01/10/2020 10:11:12 a m
## 5 5 2.393486 -76.71121 01/10/2020 10:11:12 a m
## 6 6 2.393441 -76.71126 01/10/2020 10:11:12 a m
## Psychro_Wet_Bulb_Temperature Station_Pressure Relative_Humidity Crosswind
## 1 22.0 825.1 85.2 0.0
## 2 21.4 825.3 84.0 0.0
## 3 21.8 825.5 79.6 0.2
## 4 22.8 825.4 77.6 0.4
## 5 22.6 825.2 76.5 0.0
## 6 21.5 825.0 77.7 0.3
## Temperature Barometric_Pressure Headwind Direction_True Direction_Mag
## 1 23.9 825.2 0.0 313 312
## 2 23.5 825.2 0.0 317 317
## 3 24.5 825.5 0.4 338 337
## 4 25.9 825.4 0.2 299 299
## 5 26.0 825.2 0.0 265 264
## 6 24.5 825.0 0.0 265 264
## Wind_Speed Heat_Stress_Index Altitude Dew_Point Density_Altitude Wind_Chill
## 1 0.0 25.3 1696 21.3 2.504 23.9
## 2 0.0 24.8 1696 20.7 2.485 23.5
## 3 0.5 25.7 1694 20.8 2.518 24.5
## 4 0.5 28.1 1694 21.7 2.572 25.9
## 5 0.0 28.0 1696 21.5 2.575 25.9
## 6 0.3 25.5 1698 20.4 2.522 24.5
## Estado_Fenologico_Predominante Frutos_Afectados FECHA
## 1 717 0 2020-10-01
## 2 717 0 2020-10-01
## 3 717 0 2020-10-01
## 4 717 0 2020-10-01
## 5 717 0 2020-10-01
## 6 717 0 2020-10-01
# resumen estadístico de la temperatura
summary(datos_2020$Temperature)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 22.20 24.50 25.80 25.83 27.18 29.70
# Histograma
hist(datos_2020$Temperature,
main = "Histograma de la Temperatura (01/10/2020)",
xlab = "Temperatura (°C)",
col = "lightblue")
# Boxplot simple
boxplot(datos_2020$Temperature,
main = "Boxplot de la Temperatura (°C)",
horizontal = TRUE,
col = "lightgreen")
# Gráfico de dispersión (coordenadas de los árboles)
plot(datos_2020$Longitude, datos_2020$Latitude,
main = "Distribución espacial de los árboles (01/10/2020)",
xlab = "Longitud", ylab = "Latitud",
pch = 20, col = "darkgreen")
En la primera exploración de los datos del 1 de octubre de 2020, se observaron 534 registros correspondientes a árboles de aguacate georreferenciados. La temperatura varía entre 22.2 °C y 29.7 °C, con un promedio cercano a 25.8 °C. El histograma muestra una distribución aproximadamente simétrica, aunque con una ligera concentración de valores entre 24 °C y 27 °C, lo que sugiere condiciones térmicas relativamente homogéneas en la zona. El boxplot no evidencia valores atípicos extremos, indicando que las mediciones son consistentes.
En el mapa de dispersión se observa una disposición ordenada de los puntos, que corresponde a la ubicación espacial de los árboles muestreados en el predio o zona de estudio. Esta distribución es fundamental para aplicar los métodos de geoestadística, ya que muestra una cobertura regular del área.
# Creamos el objeto tipo geoR
geodatos_temp <- as.geodata(datos_2020,
coords.col = c("Longitude", "Latitude"),
data.col = "Temperature")
# Resumen del objeto
summary(geodatos_temp)
## Number of data points: 534
##
## Coordinates summary
## Longitude Latitude
## min -76.71180 2.392101
## max -76.71022 2.393634
##
## Distance summary
## min max
## 1.711724e-05 1.959127e-03
##
## Data summary
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 22.20000 24.50000 25.80000 25.82903 27.17500 29.70000
# Visualización básica del objeto geodato
plot(geodatos_temp)
# Modelo lineal simple de temperatura respecto a coordenadas
tendencia <- lm(geodatos_temp$data ~ geodatos_temp$coords[,1] + geodatos_temp$coords[,2])
summary(tendencia)
##
## Call:
## lm(formula = geodatos_temp$data ~ geodatos_temp$coords[, 1] +
## geodatos_temp$coords[, 2])
##
## Residuals:
## Min 1Q Median 3Q Max
## -4.0761 -1.1765 -0.0286 1.1375 4.1201
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -59583.4 19009.2 -3.134 0.001817 **
## geodatos_temp$coords[, 1] -799.3 244.1 -3.274 0.001130 **
## geodatos_temp$coords[, 2] -712.4 213.0 -3.345 0.000882 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.7 on 531 degrees of freedom
## Multiple R-squared: 0.08257, Adjusted R-squared: 0.07911
## F-statistic: 23.89 on 2 and 531 DF, p-value: 1.157e-10
Con la función as.geodata() se construyó el objeto geoespacial que combina las coordenadas de los árboles y sus valores de temperatura. En el resumen del objeto se observa que el área de estudio se encuentra entre las coordenadas −76.7118 y −76.7102 de longitud y 2.3921 a 2.3936 de latitud, con 534 mediciones válidas.
Posteriormente se evaluó la posible tendencia espacial de la temperatura mediante un modelo lineal simple, considerando la longitud y la latitud como variables explicativas. Los resultados muestran que ambos coeficientes son estadísticamente significativos (p < 0.01), lo que indica que existe una leve tendencia espacial: la temperatura varía ligeramente con la ubicación.
Sin embargo, el valor de R² ≈ 0.08 sugiere que esta tendencia explica una proporción reducida de la variación total, por lo que la estructura espacial de la variable deberá analizarse con mayor detalle a través del semivariograma.
# Calcular distancias (para referencia)
summary(dist(geodatos_temp$coords))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.712e-05 4.051e-04 6.408e-04 6.827e-04 9.178e-04 1.959e-03
# Crear el semivariograma experimental
variograma_temp <- variog(geodatos_temp, max.dist = 0.0015) # el valor puede ajustarse según la escala
## variog: computing omnidirectional variogram
plot(variograma_temp, main = "Semivariograma experimental - Temperatura")
# Crear una envolvente por simulación (para ver significancia de autocorrelación)
variograma_env <- variog.mc.env(geodatos_temp, obj.var = variograma_temp, nsim = 99)
## variog.env: generating 99 simulations by permutating data values
## variog.env: computing the empirical variogram for the 99 simulations
## variog.env: computing the envelops
plot(variograma_temp)
lines(variograma_env$u, variograma_env$upper, lty = 2)
lines(variograma_env$u, variograma_env$lower, lty = 2)
A partir del conjunto de datos del 1 de octubre de 2020 se construyó el semivariograma experimental de la temperatura. En el gráfico se observa que la semivarianza aumenta a medida que lo hace la distancia entre los puntos, alcanzando una meseta aproximadamente a partir de los 0.001 grados de separación.
Este comportamiento indica la presencia de autocorrelación espacial positiva, es decir, las mediciones de temperatura tomadas en árboles cercanos tienden a ser más similares que aquellas más distantes. La forma del variograma sugiere la existencia de una estructura espacial definida, lo cual permite continuar con el ajuste de un modelo teórico de variograma (exponencial, esférico o gaussiano) para posteriormente realizar la interpolación espacial mediante kriging.
# Creamos una grilla de valores iniciales
ini.vals <- expand.grid(seq(8, 12, length = 10),
seq(6e-04, 8e-04, length = 10))
# Visualizamos el variograma experimental
plot(variograma_temp)
# Modelo Exponencial
model_exp <- variofit(variograma_temp,
ini = ini.vals,
cov.model = "exponential",
wei = "npair",
min = "optim")
## variofit: covariance model used is exponential
## variofit: weights used: npairs
## variofit: minimisation function used: optim
## variofit: searching for best initial value ... selected values:
## sigmasq phi tausq kappa
## initial.value "8" "0" "0" "0.5"
## status "est" "est" "est" "fix"
## loss value: 331571.360898001
# Modelo Gaussiano
model_gaus <- variofit(variograma_temp,
ini = ini.vals,
cov.model = "gaussian",
wei = "npair",
min = "optim",
nugget = 0)
## variofit: covariance model used is gaussian
## variofit: weights used: npairs
## variofit: minimisation function used: optim
## variofit: searching for best initial value ... selected values:
## sigmasq phi tausq kappa
## initial.value "8" "0" "0" "0.5"
## status "est" "est" "est" "fix"
## loss value: 557739.825951394
# Modelo Esférico
model_esf <- variofit(variograma_temp,
ini = ini.vals,
cov.model = "spheric",
fix.nug = TRUE,
wei = "npair",
min = "optim")
## variofit: covariance model used is spherical
## variofit: weights used: npairs
## variofit: minimisation function used: optim
## variofit: searching for best initial value ... selected values:
## sigmasq phi tausq kappa
## initial.value "8" "0" "0" "0.5"
## status "est" "est" "fix" "fix"
## loss value: 1942538.50492307
# Agregamos las líneas de los tres modelos al gráfico
lines(model_exp, col = "blue", lwd = 2)
lines(model_gaus, col = "red", lwd = 2)
lines(model_esf, col = "purple", lwd = 2)
# Agregamos una leyenda
legend("bottomright",
legend = c("Exponencial", "Gaussiano", "Esférico"),
col = c("blue", "red", "purple"),
lwd = 2)
Se realizó el ajuste de tres modelos teóricos de semivarianza: exponencial, gaussiano y esférico, utilizando el método de mínimos cuadrados ponderados con valores iniciales definidos en una grilla. En el gráfico se observa que el modelo exponencial (línea azul) sigue más de cerca la tendencia del semivariograma experimental, especialmente en las distancias cortas, donde la autocorrelación espacial es más fuerte.
Los resultados numéricos también confirman este comportamiento: el modelo exponencial presentó el menor valor del error del ajuste (loss value = 331 571), mientras que los modelos gaussiano y esférico mostraron errores considerablemente mayores.
Por lo tanto, el modelo exponencial fue seleccionado como el que mejor representa la estructura espacial de la variable temperatura, y se utilizará como base para la interpolación espacial mediante el método de kriging.
# Revisamos los rangos de coordenadas
range_long <- range(geodatos_temp$coords[,1])
range_lat <- range(geodatos_temp$coords[,2])
range_long
## [1] -76.71180 -76.71022
range_lat
## [1] 2.392101 2.393634
# Creamos la cuadrícula de predicción (100 x 100 puntos)
geodatos_grid <- expand.grid(
lon = seq(range_long[1], range_long[2], length = 100),
lat = seq(range_lat[1], range_lat[2], length = 100)
)
# Visualizamos la malla
plot(geodatos_grid, pch = ".", main = "Malla de predicción (100x100)")
points(geodatos_temp$coords, col = "red", pch = 20)
# modelo exp
model_exp$cov.pars
## [1] 8.000000202 0.001755716
model_exp$nugget
## [1] 1.123523e-06
geodatos_ko <- krige.conv(
geodata = geodatos_temp,
loc = geodatos_grid,
krige = krige.control(
nugget = model_exp$nugget,
trend.d = "cte",
trend.l = "cte",
cov.pars = model_exp$cov.pars, # parámetros del modelo
cov.model = "exponential" # modelo elegido
)
)
## krige.conv: model with constant mean
## krige.conv: Kriging performed using global neighbourhood
Para la interpolación se generó una malla regular de predicción de 100×100 puntos que cubre la extensión de las coordenadas observadas (longitud entre −76.71180 y −76.71022, latitud entre 2.392101 y 2.393634). La malla permite estimar la temperatura en una superficie continua; la densidad de puntos muestreados (puntos rojos) es mayor en el interior del dominio, por lo que las predicciones son más confiables en esa zona que en los bordes.
#Visualización
par(mfrow = c(1, 2))
# ️Mapa de predicción
image(geodatos_ko,
main = "Predicción de Temperatura-K",
xlab = "Longitud", ylab = "Latitud")
contour(geodatos_ko, add = TRUE, drawlabels = TRUE)
# Mapa de desviación estándar (incertidumbre)
image(geodatos_ko,
main = "Desv.estándar de la predicción-K",
val = sqrt(geodatos_ko$krige.var),
xlab = "Longitud", ylab = "Latitud")
contour(geodatos_ko, val = sqrt(geodatos_ko$krige.var), add = TRUE, drawlabels = TRUE)
El mapa de predicción revela un patrón espacial no homogéneo: se observan áreas con temperaturas ligeramente más altas y otras más bajas, organizadas en una estructura continua que sugiere gradientes locales. El modelo exponencial utilizado (sigmasq ≈ 8, rango ≈ 0.00175°) indica que la dependencia espacial tiene alcance en torno a ~200 m; por tanto, las variaciones observadas son consistentes con procesos que actúan a esa escala.
El mapa de desviación estándar muestra que la incertidumbre de la estimación es menor en las áreas con mayor densidad de muestreo y aumenta hacia los bordes del dominio. Esto es consistente con la naturaleza del kriging: la precisión es mayor donde hay puntos observados cercanos y decrece en zonas poco muestreadas. El patrón de incertidumbre sugiere que se debe tener más cautela al interpretar las predicciones en los límites del área de estudio.
En conclusión, la variable temperatura presenta estructura espacial significativa y fue posible modelarla mediante un variograma experimental ajustado con un modelo exponencial. El kriging ordinario aplicado con los parámetros estimados permitió generar un mapa de predicción espacial que muestra gradientes térmicos dentro del área de estudio; la incertidumbre asociada es menor en las zonas con mayor densidad de muestreo y mayor en los límites del dominio.