1 Introducción

Este informe presenta un análisis geoestadístico aplicado a mediciones ambientales registradas en árboles de producción de aguacate en el departamento del Cauca. Los datos incluyen variables como temperatura, humedad relativa, velocidad del viento y altitud, tomadas en las ubicaciones georreferenciadas de cada árbol.

El objetivo central es interpolar espacialmente la variable temperatura para la fecha 01/10/2020, con el fin de generar un mapa de predicción continua dentro de la finca. Esto permite identificar zonas con condiciones térmicas diferenciadas que puedan ser relevantes para el manejo agronómico del cultivo.

El análisis sigue el flujo metodológico visto en clase:

  1. Análisis exploratorio de los datos
  2. Construcción del objeto geoestadístico (geodata)
  3. Evaluación de tendencia espacial
  4. Cálculo e interpretación del semivariograma experimental
  5. Ajuste y comparación de modelos teóricos
  6. Predicción espacial mediante Kriging
  7. Generación del mapa final de interpolación

2 Carga de Librerías

# ── Manipulación de datos ────────────────────────────────────────────────────
library(readxl)       # Leer archivos Excel
library(dplyr)        # Manipulación y filtrado de datos
library(janitor)      # Limpieza de nombres de columnas
library(stringr)      # Manejo de cadenas de texto (fechas)

# ── Geoestadística (paquete central del curso) ───────────────────────────────
library(geoR)         # as.geodata(), variog(), variofit(), krige.conv()

# ── Visualización ────────────────────────────────────────────────────────────
library(ggplot2)      # Gráficos de calidad
library(viridis)      # Paletas de color perceptualmente uniformes
library(RColorBrewer) # Paletas adicionales

# ── Tablas ───────────────────────────────────────────────────────────────────
library(knitr)
library(kableExtra)

3 Importación y Revisión Inicial de los Datos

3.1 Carga del archivo Excel

# Cargar el archivo Excel (está en la raíz del proyecto)
datos_raw <- read_excel("Datos_Completos_Aguacate.xlsx")

# Limpiar nombres de columnas: eliminar espacios, tildes y caracteres especiales
datos_raw <- clean_names(datos_raw)

# Verificar dimensiones
cat("=== DIMENSIONES DE LA BASE ===\n")
## === DIMENSIONES DE LA BASE ===
cat("Filas (registros):", nrow(datos_raw), "\n")
## Filas (registros): 20271
cat("Columnas (variables):", ncol(datos_raw), "\n")
## Columnas (variables): 21

La base contiene 20.271 registros distribuidos en 21 variables, correspondientes a mediciones ambientales tomadas en múltiples fechas sobre árboles de aguacate en el Cauca. El tamaño de la base confirma que se trata de un monitoreo continuo, del cual se extraerá únicamente la fecha de interés.

3.2 Revisión de nombres de columnas

# Ver todos los nombres de columnas tras la limpieza con janitor
cat("=== NOMBRES DE COLUMNAS ===\n")
## === NOMBRES DE COLUMNAS ===
print(names(datos_raw))
##  [1] "id_arbol"                       "latitude"                      
##  [3] "longitude"                      "formatted_date_time"           
##  [5] "psychro_wet_bulb_temperature"   "station_pressure"              
##  [7] "relative_humidity"              "crosswind"                     
##  [9] "temperature"                    "barometric_pressure"           
## [11] "headwind"                       "direction_true"                
## [13] "direction_mag"                  "wind_speed"                    
## [15] "heat_stress_index"              "altitude"                      
## [17] "dew_point"                      "density_altitude"              
## [19] "wind_chill"                     "estado_fenologico_predominante"
## [21] "frutos_afectados"

Los nombres de columnas quedaron correctamente estandarizados por janitor (minúsculas, sin espacios ni caracteres especiales). Se identifican las columnas clave: latitude y longitude como coordenadas espaciales, formatted_date_time como variable de fecha en texto, y temperature como variable principal del análisis. La base cuenta además con variables ambientales complementarias (relative_humidity, wind_speed, altitude) que podrían usarse si la temperatura no presenta estructura espacial.

3.3 Estructura y tipos de datos

# Resumen de estructura: tipo de cada variable
cat("=== ESTRUCTURA DE LA BASE ===\n")
## === ESTRUCTURA DE LA BASE ===
str(datos_raw)
## tibble [20,271 × 21] (S3: tbl_df/tbl/data.frame)
##  $ id_arbol                      : chr [1:20271] "1" "2" "3" "4" ...
##  $ latitude                      : num [1:20271] 2.38 2.38 2.38 2.38 2.38 ...
##  $ longitude                     : num [1:20271] -76.6 -76.6 -76.6 -76.6 -76.6 ...
##  $ formatted_date_time           : chr [1:20271] "21/08/2019  9:22:57 a, m," "21/08/2019  9:27:13 a, m," "21/08/2019  9:36:36 a, m," "21/08/2019  9:38:02 a, m," ...
##  $ psychro_wet_bulb_temperature  : num [1:20271] 14.8 11.6 12.9 14.1 14.3 14.2 14.4 12.8 15 14 ...
##  $ station_pressure              : num [1:20271] 805 805 806 806 805 ...
##  $ relative_humidity             : num [1:20271] 33.6 36.8 31.5 33.2 34.3 33.8 34.9 34.2 33.6 34 ...
##  $ crosswind                     : num [1:20271] 0.2 3.6 0.4 0.6 0.4 0.5 0.6 2.9 0.4 0.7 ...
##  $ temperature                   : num [1:20271] 25.7 20.8 23.7 25 25 25 24.9 22.9 26.2 24.6 ...
##  $ barometric_pressure           : num [1:20271] 805 805 806 806 805 ...
##  $ headwind                      : num [1:20271] 0.7 3.5 0.7 0.7 0.4 0.1 0 2.2 0.2 0.7 ...
##  $ direction_true                : num [1:20271] 166 314 332 139 129 83 93 128 118 137 ...
##  $ direction_mag                 : num [1:20271] 165 313 331 139 128 83 92 127 118 137 ...
##  $ wind_speed                    : num [1:20271] 0.8 5.1 0.8 0.9 0.6 0.5 0.6 3.7 0.5 1 ...
##  $ heat_stress_index             : num [1:20271] 24.1 19.5 22 23.2 23.3 23.3 23.2 21.5 24.6 22.9 ...
##  $ altitude                      : num [1:20271] 1896 1895 1889 1890 1894 ...
##  $ dew_point                     : num [1:20271] 8.6 5.5 5.8 7.7 8.1 7.9 8.3 6.3 8.9 7.7 ...
##  $ density_altitude              : num [1:20271] 2.74 2.57 2.66 2.71 2.71 ...
##  $ wind_chill                    : num [1:20271] 25.7 20.8 23.7 24.9 24.9 24.9 24.8 22.9 26.2 24.5 ...
##  $ estado_fenologico_predominante: num [1:20271] 715 715 715 715 715 715 715 715 715 715 ...
##  $ frutos_afectados              : num [1:20271] 0 3 0 0 1 0 0 0 0 21 ...

Todas las variables ambientales son de tipo numérico (num), lo que confirma que están listas para el análisis geoestadístico sin necesidad de conversión. La columna id_arbol es de tipo carácter (chr), lo cual es correcto pues actúa como identificador. Las coordenadas presentan valores coherentes con la ubicación geográfica de la finca: latitudes alrededor de 2.38° y longitudes alrededor de −76.6°, lo que corresponde a la zona rural del municipio de Popayán, Cauca.

3.4 Primeras filas

# Vista de las primeras 6 filas
head(datos_raw, 6)

3.5 Identificación de columnas clave

# Identificar columna de fecha, coordenadas y temperatura
cat("=== COLUMNAS CLAVE ===\n")
## === COLUMNAS CLAVE ===
cat("Fecha          : formatted_date_time\n")
## Fecha          : formatted_date_time
cat("Latitud (Y)    : latitude\n")
## Latitud (Y)    : latitude
cat("Longitud (X)   : longitude\n")
## Longitud (X)   : longitude
cat("Temperatura    : temperature\n")
## Temperatura    : temperature
cat("\n")
# Muestra de la columna de fecha para confirmar formato
cat("=== MUESTRA DE LA COLUMNA DE FECHA ===\n")
## === MUESTRA DE LA COLUMNA DE FECHA ===
print(head(datos_raw$formatted_date_time, 10))
##  [1] "21/08/2019  9:22:57 a, m," "21/08/2019  9:27:13 a, m,"
##  [3] "21/08/2019  9:36:36 a, m," "21/08/2019  9:38:02 a, m,"
##  [5] "21/08/2019  9:39:38 a, m," "21/08/2019  9:42:02 a, m,"
##  [7] "21/08/2019  9:43:40 a, m," "21/08/2019  9:46:01 a, m,"
##  [9] "21/08/2019  9:47:49 a, m," "21/08/2019  9:49:22 a, m,"

4 Filtrado por Fecha: 01/10/2020

4.1 Extracción de la fecha y filtro

La columna formatted_date_time contiene texto con formato dd/mm/yyyy hh:mm:ss. Se extrae la parte de fecha (primeros 10 caracteres) para filtrar.

# Extraer los primeros 10 caracteres de la columna de fecha
# El formato observado es "01/10/2020 ..."
datos_raw <- datos_raw %>%
  mutate(fecha_solo = str_trim(str_sub(formatted_date_time, 1, 10)))

# Filtrar únicamente la fecha objetivo
datos_filtrados <- datos_raw %>%
  filter(fecha_solo == "01/10/2020")

# Validar número de registros (debe ser 534)
cat("=== VALIDACIÓN DE REGISTROS ===\n")
## === VALIDACIÓN DE REGISTROS ===
cat("Registros para 01/10/2020:", nrow(datos_filtrados), "\n")
## Registros para 01/10/2020: 534
if (nrow(datos_filtrados) == 534) {
  cat("✔ Correcto: se tienen exactamente 534 registros.\n")
} else {
  cat("⚠ Atención: el número de registros no es 534. Revisar formato de fecha.\n")
}
## ✔ Correcto: se tienen exactamente 534 registros.

El filtrado por fecha 01/10/2020 arrojó exactamente 534 registros, confirmando la integridad del proceso de extracción. Este tamaño muestral es adecuado para el análisis geoestadístico: suficiente para estimar el semivariograma con estabilidad estadística en múltiples lags, pero manejable computacionalmente para el kriging.

4.2 Selección de columnas de trabajo

# Seleccionar solo las columnas necesarias para el análisis
geo_datos <- datos_filtrados %>%
  select(
    id_arbol,
    latitude,
    longitude,
    temperature,
    relative_humidity,
    wind_speed,
    altitude
  ) %>%
  # Renombrar para mayor claridad
  rename(
    Latitude          = latitude,
    Longitude         = longitude,
    Temperature       = temperature,
    Relative_Humidity = relative_humidity,
    Wind_Speed        = wind_speed,
    Altitude          = altitude
  )

cat("=== BASE DE TRABAJO ===\n")
## === BASE DE TRABAJO ===
cat("Filas:", nrow(geo_datos), "\n")
## Filas: 534
cat("Columnas:", ncol(geo_datos), "\n")
## Columnas: 7
head(geo_datos, 10)

La base de trabajo final contiene 534 árboles con sus coordenadas geográficas y las variables ambientales de interés. Los primeros registros muestran temperaturas entre 23.5°C y 26.0°C, con humedades relativas elevadas (75–85%) y velocidades de viento bajas o nulas, lo que es consistente con condiciones de mañana en un cultivo de ladera en el Cauca. La altitud es prácticamente constante en los primeros registros (~1.694–1.698 m.s.n.m.), lo que sugiere que la finca tiene poca variación altitudinal en esa zona — dato relevante para interpretar la estructura espacial de la temperatura más adelante.


5 Análisis Exploratorio de la Variable Temperatura

5.1 Verificación de valores faltantes

cat("=== VALORES FALTANTES POR VARIABLE ===\n")
## === VALORES FALTANTES POR VARIABLE ===
sapply(geo_datos, function(x) sum(is.na(x))) %>%
  as.data.frame() %>%
  setNames("NA_count") %>%
  kable(caption = "Tabla 1. Valores faltantes por variable") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE)
Tabla 1. Valores faltantes por variable
NA_count
id_arbol 0
Latitude 0
Longitude 0
Temperature 0
Relative_Humidity 0
Wind_Speed 0
Altitude 0

La base de trabajo está completamente limpia: ninguna de las 7 variables presenta valores faltantes (NA_count = 0 en todas). Esto es ideal para el análisis geoestadístico, ya que geoR no admite datos faltantes en las coordenadas ni en la variable de interés. No será necesario aplicar ningún procedimiento de imputación antes de construir el objeto geodata.

5.2 Estadísticos descriptivos de temperatura

cat("=== ESTADÍSTICOS DESCRIPTIVOS: TEMPERATURA ===\n")
## === ESTADÍSTICOS DESCRIPTIVOS: TEMPERATURA ===
summary(geo_datos$Temperature)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   22.20   24.50   25.80   25.83   27.18   29.70
cat("\nDesviación estándar:", round(sd(geo_datos$Temperature, na.rm = TRUE), 3), "\n")
## 
## Desviación estándar: 1.771
cat("Coeficiente de variación (%):",
    round(100 * sd(geo_datos$Temperature, na.rm = TRUE) /
            mean(geo_datos$Temperature, na.rm = TRUE), 2), "%\n")
## Coeficiente de variación (%): 6.86 %

La temperatura del 01/10/2020 presenta una media de 25.83°C y una mediana de 25.80°C, valores muy cercanos entre sí, lo que sugiere una distribución relativamente simétrica. El rango va de 22.2°C a 29.7°C, con una desviación estándar de 1.771°C.

El coeficiente de variación (CV) es de apenas 6.86%, lo cual indica una variabilidad baja en términos relativos. Esto significa que la temperatura no varía dramáticamente dentro de la finca, pero el rango absoluto de 7.5°C (de 22.2 a 29.7) sí es suficiente para que exista estructura espacial detectable. Un CV bajo no impide el análisis geoestadístico: lo que importa es si esa variación está espacialmente organizada, lo cual se evaluará con el semivariograma.

5.3 Histograma y densidad de temperatura

ggplot(geo_datos, aes(x = Temperature)) +
  geom_histogram(aes(y = ..density..),
                 bins = 25,
                 fill = "#2C7FB8",
                 color = "white",
                 alpha = 0.8) +
  geom_density(color = "#D7191C", linewidth = 1) +
  labs(
    title    = "Figura 1. Distribución de la Temperatura – 01/10/2020",
    subtitle = "Finca de aguacate, Cauca",
    x        = "Temperatura (°C)",
    y        = "Densidad"
  ) +
  theme_minimal(base_size = 13) +
  theme(plot.title = element_text(face = "bold"))

El histograma muestra una distribución con dos concentraciones principales de frecuencia: una zona más densa alrededor de los 25–26°C (donde se encuentra la mayor parte de los registros) y una cola hacia valores altos que llega hasta los 29.7°C. La curva de densidad revela una forma bimodal suave, con un primer pico cerca de 24°C y un segundo pico más pronunciado cerca de 26°C. Esta forma bimodal puede reflejar la existencia de dos zonas microclimáticas diferenciadas dentro de la finca, lo cual es precisamente el tipo de variación espacial que el kriging buscará modelar y mapear.

La distribución no es perfectamente normal, pero la desviación es moderada. geoR trabaja bien bajo estas condiciones sin necesidad de transformación.

5.4 Diagrama de cajas (boxplot) – detección de atípicos

ggplot(geo_datos, aes(y = Temperature)) +
  geom_boxplot(fill = "#41B6C4", color = "#253494",
               outlier.color = "red", outlier.size = 2.5) +
  labs(
    title    = "Figura 2. Boxplot de Temperatura – 01/10/2020",
    subtitle = "Los puntos rojos indican posibles valores atípicos",
    y        = "Temperatura (°C)",
    x        = ""
  ) +
  theme_minimal(base_size = 13) +
  theme(plot.title = element_text(face = "bold"))

El boxplot confirma lo observado en los estadísticos descriptivos: la caja intercuartílica se extiende entre 24.5°C (Q1) y 27.18°C (Q3), con una mediana en 25.8°C. Los bigotes alcanzan los valores extremos de 22.2°C y 29.7°C.

No se observan valores atípicos (puntos rojos fuera de los bigotes), lo que indica que todos los registros de temperatura son coherentes y están dentro de un rango esperable para la zona y la fecha. Esto es favorable porque los outliers extremos pueden distorsionar el semivariograma experimental y producir estimaciones de kriging poco confiables. La base está lista para avanzar sin necesidad de filtrar registros.

Nota: El eje X del boxplot no tiene significado en este gráfico (es solo el espacio de dispersión interno de ggplot2); el análisis se centra exclusivamente en el eje Y (temperatura).

5.5 Distribución espacial de los árboles

ggplot(geo_datos, aes(x = Longitude, y = Latitude)) +
  geom_point(color = "#1D6A3A", size = 1.5, alpha = 0.6) +
  labs(
    title    = "Figura 3. Distribución espacial de los árboles",
    subtitle = "Finca de aguacate, Cauca – 01/10/2020",
    x        = "Longitud",
    y        = "Latitud"
  ) +
  theme_minimal(base_size = 13) +
  theme(plot.title = element_text(face = "bold")) +
  coord_fixed()

La finca presenta una distribución espacial de árboles relativamente regular y densa, con una forma irregular que se extiende principalmente en dirección norte (latitudes 2.392–2.394) con mayor densidad en el sector noreste. La extensión espacial es pequeña: aproximadamente 0.0015° en latitud y 0.0012° en longitud, lo que equivale a unos 130–170 metros en cada dirección. Este es un dato crítico: las distancias entre árboles son muy cortas (del orden de metros), lo que significa que el rango del semivariograma también será pequeño, y los lags del variograma deben definirse cuidadosamente en esa escala.

5.6 Mapa inicial de temperatura (mapa de puntos)

ggplot(geo_datos, aes(x = Longitude, y = Latitude, color = Temperature)) +
  geom_point(size = 2.5, alpha = 0.85) +
  scale_color_viridis_c(
    option = "plasma",
    name   = "Temperatura\n(°C)"
  ) +
  labs(
    title    = "Figura 4. Mapa inicial de temperatura",
    subtitle = "Distribución espacial de la temperatura – 01/10/2020",
    x        = "Longitud",
    y        = "Latitud"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title   = element_text(face = "bold"),
    legend.position = "right"
  ) +
  coord_fixed()

El mapa inicial de temperatura revela un patrón espacial visualmente claro: los valores más altos de temperatura (amarillos/naranjas, ~28–29°C) se concentran en el sector oeste y suroccidente de la finca, mientras que los valores más bajos (violeta/azul, ~22–24°C) se ubican principalmente en la zona central y nororiental.

Este patrón es el hallazgo más importante del análisis exploratorio: los puntos cercanos entre sí tienden a compartir colores similares, lo que constituye evidencia visual directa de autocorrelación espacial positiva. Esta es exactamente la condición necesaria para que el semivariograma muestre estructura y para que el kriging sea un método de interpolación adecuado, ya
que permite ya que permite incorporar la estructura de autocorrelación espacial observada en los datos

El gradiente térmico observable de oeste a este sugiere la posible existencia de tendencia espacial, la cual será evaluada formalmente en la siguiente sección.


6 Creación del Objeto Geoestadístico (geodata)

El paquete geoR trabaja con un objeto de clase geodata, que integra las coordenadas y la variable de interés en una estructura unificada. La función as.geodata() requiere indicar las columnas de coordenadas y la columna de datos.

En nuestro caso, el dataframe geo_datos tiene: - Columna 3: Longitude (coordenada X) - Columna 2: Latitude (coordenada Y) - Columna 4: Temperature (variable de interés)

# Crear el objeto geodata con as.geodata()
# coords.col = c(col_X, col_Y) — en geoR, el primer coord es X (Longitud), segundo Y (Latitud)
# data.col   = columna de la variable de interés (Temperature)

geo_temp <- as.geodata(
  obj        = as.data.frame(geo_datos),
  coords.col = c(3, 2),   # columna 3 = Longitude (X), columna 2 = Latitude (Y)
  data.col   = 4          # columna 4 = Temperature
)

# Verificar el objeto creado
cat("=== RESUMEN DEL OBJETO geodata ===\n")
## === RESUMEN DEL OBJETO geodata ===
summary(geo_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

El objeto geodata se construyó correctamente con 534 puntos de datos. Las coordenadas quedan registradas con Longitud en el rango [−76.7118, −76.7102] y Latitud en [2.3921, 2.3936], confirmando que la finca tiene una extensión espacial reducida (~218 m en su diagonal máxima). El resumen de la variable data reproduce exactamente los estadísticos del análisis exploratorio (min = 22.2°C, media = 25.83°C, max = 29.7°C), lo que confirma que la temperatura quedó correctamente asociada al objeto geoestadístico y está lista para el análisis de variograma y kriging.

6.1 Gráfico diagnóstico del objeto geodata

Figura 5. Diagnóstico del objeto geodata – Temperatura (01/10/2020)

# plot.geodata() de geoR genera 4 paneles automáticamente.
# El título se coloca como texto markdown encima (no dentro del código)
# porque geoR resetea par() internamente y no admite main ni mtext.

# Paneles generados:
# 1. Mapa de puntos coloreados por cuartil de temperatura
# 2. Dispersión Y (Latitud) vs. Temperatura  
# 3. Dispersión X (Longitud) vs. Temperatura
# 4. Histograma con curva de densidad
plot(geo_temp)

Panel superior izquierdo (mapa por cuartiles): Los 534 árboles aparecen organizados en franjas diagonales de color que recorren la finca de suroeste a noreste. Los valores más altos (rojo, cuartil superior) se concentran en el sector occidental, mientras que los valores más bajos (azul, cuartil inferior) dominan la zona central y nororiental. Este patrón en franjas es evidencia visual clara de estructura espacial organizada, lo que justifica el uso del kriging como método de interpolación.

Panel superior derecho (Latitud vs. Temperatura): La nube de puntos muestra que en latitudes bajas (~2.392, sector sur) se concentran los valores más altos de temperatura (~27–30°C), mientras que hacia latitudes altas (~2.3935) los valores tienden a ser menores. La dispersión no es aleatoria, lo que sugiere una posible tendencia norte-sur que será evaluada formalmente en la Sección 7.

Panel inferior izquierdo (Longitud vs. Temperatura): Es el panel más revelador: los valores altos de temperatura (~27–30°C) aparecen principalmente en las longitudes más occidentales (~−76.7115), con una tendencia descendente clara hacia el este (~−76.7103). Este gradiente oeste-este es el patrón dominante en la estructura espacial de la temperatura y coincide con lo observado en la Figura 4.

Panel inferior derecho (histograma): Confirma la distribución bimodal suave ya identificada en la Sección 5, con un primer modo cerca de 24°C y un segundo modo más pronunciado alrededor de 26°C. La distribución es moderadamente asimétrica hacia la derecha pero no requiere transformación para trabajar con geoR.

6.2 Verificación de distancias entre puntos

# Calcular resumen de distancias entre pares de puntos
# Esto es fundamental para definir el número de lags del semivariograma
dist_resumen <- summary(dist(as.data.frame(geo_datos)[, c("Longitude", "Latitude")]))

cat("=== DISTANCIAS ENTRE PARES DE PUNTOS ===\n")
## === DISTANCIAS ENTRE PARES DE PUNTOS ===
print(dist_resumen)
##      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
cat("\nLa distancia máxima es la extensión total de la finca.\n")
## 
## La distancia máxima es la extensión total de la finca.
cat("Se recomienda calcular el semivariograma hasta la mitad de esa distancia (max/2).\n")
## Se recomienda calcular el semivariograma hasta la mitad de esa distancia (max/2).

Las distancias entre pares de árboles son muy cortas, coherentes con una finca de escala local. La distancia mínima es de 1.71 × 10⁻⁵ grados (~1.9 m) y la máxima es de 1.96 × 10⁻³ grados (~218 m). La distancia mediana de 6.4 × 10⁻⁴ grados (~71 m) indica que la mayoría de los pares de árboles están relativamente cerca entre sí, lo que es favorable para estimar el semivariograma con buena cantidad de pares en cada lag.

Para el semivariograma se trabajará hasta la mitad de la distancia máxima (~9.8 × 10⁻⁴ grados, equivalente a ~109 m). Los lags deben definirse en el orden de 10⁻⁴ grados para capturar bien la estructura espacial a esta escala de finca.


7 Evaluación de Tendencia Espacial

Antes de calcular el semivariograma, es necesario evaluar si la variable temperatura presenta tendencia espacial (gradiente sistemático en función de la ubicación). Si existe tendencia, el proceso no es estacionario de segundo orden y se debe aplicar Kriging Universal en lugar de Kriging Ordinario.

7.1 Gráficos de tendencia

par(mfrow = c(1, 2))

# Tendencia Este-Oeste (temperatura vs. Longitud)
plot(geo_datos$Longitude, geo_datos$Temperature,
     xlab = "Longitud (X)", ylab = "Temperatura (°C)",
     main = "Figura 6a. Temperatura vs. Longitud (E-O)",
     pch  = 16, col = "#2C7FB8", cex = 0.6)
abline(lm(Temperature ~ Longitude, data = geo_datos),
       col = "red", lwd = 2, lty = 2)

# Tendencia Norte-Sur (temperatura vs. Latitud)
plot(geo_datos$Latitude, geo_datos$Temperature,
     xlab = "Latitud (Y)", ylab = "Temperatura (°C)",
     main = "Figura 6b. Temperatura vs. Latitud (N-S)",
     pch  = 16, col = "#41B6C4", cex = 0.6)
abline(lm(Temperature ~ Latitude, data = geo_datos),
       col = "red", lwd = 2, lty = 2)

par(mfrow = c(1, 1))

Ambos gráficos muestran una línea de regresión con pendiente negativa clara, lo que indica que la temperatura disminuye tanto de oeste a este (Figura 6a) como de sur a norte (Figura 6b).

En la Figura 6a (Temperatura vs. Longitud), la temperatura desciende desde ~27°C en las longitudes más occidentales (~−76.7115) hasta ~25°C hacia el este (~−76.7103). Este es el gradiente más pronunciado visualmente.

En la Figura 6b (Temperatura vs. Latitud), la temperatura también decrece a medida que se avanza hacia el norte, desde valores cercanos a 27°C en latitudes bajas (~2.3921) hasta ~25°C en las latitudes más altas (~2.3936).

La presencia de pendientes negativas en ambas direcciones es un indicio visual fuerte de tendencia espacial bidireccional, que será confirmada o descartada formalmente con la prueba de regresión en la siguiente subsección.

7.2 Prueba de regresión para tendencia

# Modelo de regresión lineal: temperatura en función de las coordenadas
modelo_tendencia <- lm(Temperature ~ Longitude + Latitude, data = geo_datos)

cat("=== MODELO DE TENDENCIA ESPACIAL ===\n")
## === MODELO DE TENDENCIA ESPACIAL ===
summary(modelo_tendencia)
## 
## Call:
## lm(formula = Temperature ~ Longitude + Latitude, data = geo_datos)
## 
## 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 ** 
## Longitude     -799.3      244.1  -3.274 0.001130 ** 
## Latitude      -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

La prueba de regresión confirma que ambas coordenadas son estadísticamente significativas:

  • Longitud: coeficiente = -799.3, p-valor = 0.00113 (significativo al 1%).
  • Latitud: coeficiente = -712.4, p-valor = 0.00088 (significativo al 1%).

Ambos p-valores son menores que 0.05, lo que confirma la existencia de tendencia espacial lineal en la temperatura en las dos direcciones. Esto significa que el proceso no es estacionario de segundo orden, por lo que el kriging ordinario no sería técnicamente el más apropiado.

Por lo tanto, en la sección 9 se aplicará Kriging Universal, incorporando la tendencia lineal en el modelo y utilizando el modelo gaussiano como estructura de autocorrelación espacial, ya que fue el modelo teórico con menor suma de cuadrados en el ajuste del semivariograma.

El R² ajustado del modelo es de apenas 0.079, lo que indica que la tendencia lineal explica solo el 7.9% de la variabilidad total de la temperatura. El 92.1% restante corresponde a variación espacial no explicada por la tendencia lineal, la cual será modelada posteriormente mediante el semivariograma. Este bajo R² no invalida la existencia de tendencia; lo importante es que los coeficientes son significativos y justifican el uso de Kriging Universal.


8 Semivariograma Experimental

El semivariograma experimental mide cómo cambia la semivarianza en función de la distancia entre pares de puntos. Es la herramienta central de la geoestadística para cuantificar la autocorrelación espacial.

8.1 Cálculo del semivariograma

# Calcular distancia máxima entre puntos para definir uvec
dist_max <- max(dist(as.data.frame(geo_datos)[, c("Longitude", "Latitude")]))
dist_med <- dist_max / 2

cat("Distancia máxima entre puntos:", round(dist_max, 6), "\n")
## Distancia máxima entre puntos: 0.001959
cat("Distancia media (max/2)       :", round(dist_med, 6), "\n")
## Distancia media (max/2)       : 0.00098
# Calcular el semivariograma experimental omnidireccional
# uvec: secuencia de distancias desde 0 hasta la mitad del rango
# Se usan ~15 bins para capturar bien la estructura espacial

variograma <- variog(
  geodata = geo_temp,
  option  = "bin",
  trend   = "1st",
  uvec    = seq(0, dist_med, length.out = 16)
)
## variog: computing omnidirectional variogram
cat("\n=== RESUMEN DEL VARIOGRAMA EXPERIMENTAL ===\n")
## 
## === RESUMEN DEL VARIOGRAMA EXPERIMENTAL ===
summary(variograma)
##                  Length Class  Mode     
## u                16     -none- numeric  
## v                16     -none- numeric  
## n                16     -none- numeric  
## sd               16     -none- numeric  
## bins.lim         17     -none- numeric  
## ind.bin          16     -none- logical  
## var.mark          1     -none- numeric  
## beta.ols          3     -none- numeric  
## output.type       1     -none- character
## max.dist          1     -none- numeric  
## estimator.type    1     -none- character
## n.data            1     -none- numeric  
## lambda            1     -none- numeric  
## trend             1     -none- character
## pairs.min         1     -none- numeric  
## nugget.tolerance  1     -none- numeric  
## direction         1     -none- character
## tolerance         1     -none- character
## uvec             16     -none- numeric  
## call              5     -none- call

El semivariograma omnidireccional se calculó con 16 lags distribuidos entre 0 y 0.00098 grados (mitad de la distancia máxima), incorporando una tendencia espacial de primer orden mediante el argumento trend = "1st". Esta decisión es coherente con el análisis previo de tendencia, donde se identificó que la temperatura presenta variación asociada a las coordenadas espaciales. El objeto variog contiene los vectores u (distancias), v (semivarianzas) y n (número de pares por lag), todos con 16 valores, lo que confirma que el cálculo se realizó correctamente sobre los 534 puntos.

8.2 Gráfico del semivariograma experimental

plot(variograma,
     pch  = 16,
     col  = "#2C7FB8",
     main = "Figura 7. Semivariograma experimental – Temperatura",
     xlab = "Distancia h",
     ylab = "Semivarianza γ(h)")
title(sub = "Fecha: 01/10/2020 | Finca de aguacate, Cauca",
      cex.sub = 0.9)

El semivariograma experimental muestra un comportamiento muy claro y bien definido que permite identificar todos sus componentes:

Nugget (pepita): El primer punto del semivariograma, en la distancia más corta (~1×10⁻⁵), tiene una semivarianza de aproximadamente 1.0. Este valor no es cero, lo que indica que existe variabilidad a escala menor que el espaciado mínimo entre árboles (~1.9 m). Esta componente puede atribuirse a pequeñas variaciones microclimáticas entre árboles adyacentes o a errores menores de medición del sensor.

Crecimiento y forma: Desde el nugget, la semivarianza crece de forma continua y monotónica pasando por ~1.5 (lag 2), ~2.2 (lag 3), ~2.6–2.8 (lags 4–7), hasta alcanzar valores de ~3.0–3.2 en los lags intermedios. Este crecimiento sostenido confirma que existe autocorrelación espacial positiva: los árboles cercanos tienen temperaturas más similares entre sí que los árboles lejanos.

Sill (meseta): La semivarianza se estabiliza alrededor de 3.3–3.5 a partir de distancias de aproximadamente 8×10⁻⁴ grados (~89 m). Este valor es coherente con la varianza total de la temperatura (σ² = 1.771² ≈ 3.14), lo que confirma que el semivariograma alcanza efectivamente la meseta dentro del área de la finca.

Range (rango): La estabilización ocurre alrededor de 8×10⁻⁴ grados (~89 m). Esto significa que árboles separados por menos de ~89 m comparten cierta estructura espacial en su temperatura, mientras que a distancias mayores la temperatura puede considerarse espacialmente independiente.

Conclusión del semivariograma: La forma del semivariograma — con nugget bajo, crecimiento monotónico y meseta bien definida — es ideal para el ajuste de modelos teóricos y valida el uso de kriging como método de interpolación. En la siguiente sección se ajustarán y compararán los modelos esférico, exponencial y gaussiano.


9 Ajuste de Modelos Teóricos de Semivariograma

Se ajustan y comparan tres modelos teóricos vistos en clase: esférico, exponencial y gaussiano. La función variofit() de geoR estima los parámetros por mínimos cuadrados ponderados.

9.1 Valores iniciales

# Definir valores iniciales a partir del variograma experimental
nugget_ini <- min(variograma$v)               # pepita inicial
sill_ini   <- var(geo_datos$Temperature)      # meseta ≈ varianza total
range_ini  <- variograma$u[which.max(variograma$v)] # rango aproximado

cat("Valores iniciales para el ajuste:\n")
## Valores iniciales para el ajuste:
cat("  Nugget inicial:", round(nugget_ini, 4), "\n")
##   Nugget inicial: 1.0121
cat("  Sill inicial  :", round(sill_ini, 4), "\n")
##   Sill inicial  : 3.1367
cat("  Range inicial :", round(range_ini, 6), "\n")
##   Range inicial : 0.000849

Los valores iniciales para el ajuste se derivaron directamente del semivariograma experimental: nugget inicial = 1.013 (primer valor observado), sill inicial = 3.137 (varianza total de la temperatura) y range inicial = 0.000914 grados (~102 m, correspondiente al lag donde el variograma comienza a estabilizarse). Estos valores garantizan que el algoritmo de optimización parte de un punto razonable y reduce el riesgo de convergencia a mínimos locales.

9.2 Modelo esférico

# Ajuste del modelo esférico (spherical)
modelo_esferico <- variofit(
  vario      = variograma,
  cov.model  = "spherical",
  ini.cov.pars = c(sill_ini, range_ini),
  nugget     = nugget_ini,
  fix.nugget = FALSE,
  weights    = "npairs"
)
## variofit: covariance model used is spherical 
## variofit: weights used: npairs 
## variofit: minimisation function used: optim
cat("=== MODELO ESFÉRICO ===\n")
## === MODELO ESFÉRICO ===
summary(modelo_esferico)
## $pmethod
## [1] "WLS (weighted least squares)"
## 
## $cov.model
## [1] "spherical"
## 
## $spatial.component
##     sigmasq         phi 
## 3.136698117 0.001321435 
## 
## $spatial.component.extra
## kappa 
##   0.5 
## 
## $nugget.component
##    tausq 
## 1.012097 
## 
## $fix.nugget
## [1] FALSE
## 
## $fix.kappa
## [1] TRUE
## 
## $practicalRange
## [1] 0.001321435
## 
## $sum.of.squares
##    value 
## 29339.17 
## 
## $estimated.pars
##       tausq     sigmasq         phi 
## 1.012096515 3.136698117 0.001321435 
## 
## $weights
## [1] "npairs"
## 
## $call
## variofit(vario = variograma, ini.cov.pars = c(sill_ini, range_ini), 
##     cov.model = "spherical", fix.nugget = FALSE, nugget = nugget_ini, 
##     weights = "npairs")
## 
## attr(,"class")
## [1] "summary.variomodel"

El modelo esférico estimó un nugget = 1.01210, sill = 3.13670 y range = 0.001321 grados, con una suma de cuadrados de 29339.172. Aunque sus parámetros son positivos y tienen sentido geoestadístico, este modelo presentó un error de ajuste considerablemente mayor que el modelo gaussiano. Por tanto, no fue seleccionado como el modelo final.

9.3 Modelo exponencial

# Ajuste del modelo exponencial (exponential)
modelo_exponencial <- variofit(
  vario      = variograma,
  cov.model  = "exponential",
  ini.cov.pars = c(sill_ini, range_ini),
  nugget     = nugget_ini,
  fix.nugget = FALSE,
  weights    = "npairs"
)
## variofit: covariance model used is exponential 
## variofit: weights used: npairs 
## variofit: minimisation function used: optim
cat("=== MODELO EXPONENCIAL ===\n")
## === MODELO EXPONENCIAL ===
summary(modelo_exponencial)
## $pmethod
## [1] "WLS (weighted least squares)"
## 
## $cov.model
## [1] "exponential"
## 
## $spatial.component
##     sigmasq         phi 
## 3.136698112 0.000848955 
## 
## $spatial.component.extra
## kappa 
##   0.5 
## 
## $nugget.component
##    tausq 
## 1.012097 
## 
## $fix.nugget
## [1] FALSE
## 
## $fix.kappa
## [1] TRUE
## 
## $practicalRange
## [1] 0.002561307
## 
## $sum.of.squares
##    value 
## 35114.97 
## 
## $estimated.pars
##       tausq     sigmasq         phi 
## 1.012096505 3.136698112 0.000848955 
## 
## $weights
## [1] "npairs"
## 
## $call
## variofit(vario = variograma, ini.cov.pars = c(sill_ini, range_ini), 
##     cov.model = "exponential", fix.nugget = FALSE, nugget = nugget_ini, 
##     weights = "npairs")
## 
## attr(,"class")
## [1] "summary.variomodel"

El modelo exponencial estimó un nugget = 1.01210, sill = 3.13670 y phi = 0.000849 grados, con una suma de cuadrados de 35114.968. Aunque el modelo permite representar estructuras espaciales con crecimiento progresivo, en este caso presentó el mayor error de ajuste entre los tres modelos comparados. Por esta razón, el modelo exponencial no fue seleccionado como el modelo final.

9.4 Modelo gaussiano

# Ajuste del modelo gaussiano (gaussian)
modelo_gaussiano <- variofit(
  vario      = variograma,
  cov.model  = "gaussian",
  ini.cov.pars = c(sill_ini, range_ini),
  nugget     = nugget_ini,
  fix.nugget = FALSE,
  weights    = "npairs"
)
## variofit: covariance model used is gaussian 
## variofit: weights used: npairs 
## variofit: minimisation function used: optim
cat("=== MODELO GAUSSIANO ===\n")
## === MODELO GAUSSIANO ===
summary(modelo_gaussiano)
## $pmethod
## [1] "WLS (weighted least squares)"
## 
## $cov.model
## [1] "gaussian"
## 
## $spatial.component
##     sigmasq         phi 
## 3.507730928 0.001667965 
## 
## $spatial.component.extra
## kappa 
##   0.5 
## 
## $nugget.component
##    tausq 
## 2.645951 
## 
## $fix.nugget
## [1] FALSE
## 
## $fix.kappa
## [1] TRUE
## 
## $practicalRange
## [1] 0.002886982
## 
## $sum.of.squares
##    value 
## 8942.068 
## 
## $estimated.pars
##       tausq     sigmasq         phi 
## 2.645950671 3.507730928 0.001667965 
## 
## $weights
## [1] "npairs"
## 
## $call
## variofit(vario = variograma, ini.cov.pars = c(sill_ini, range_ini), 
##     cov.model = "gaussian", fix.nugget = FALSE, nugget = nugget_ini, 
##     weights = "npairs")
## 
## attr(,"class")
## [1] "summary.variomodel"

El modelo gaussiano estimó un nugget = 2.64595, sill = 3.50773 y range = 0.001668 grados, con una suma de cuadrados de 8942.068. Este fue el menor error de ajuste entre los modelos evaluados, por lo que el modelo gaussiano se selecciona como el más adecuado para representar la estructura espacial de la temperatura. Su comportamiento es coherente con una variación térmica suave y continua dentro de la finca.

9.5 Comparación visual de modelos

# Gráfico comparativo de los tres modelos ajustados
plot(variograma,
     pch  = 16,
     col  = "gray40",
     main = "Figura 8. Comparación de modelos teóricos – Temperatura",
     xlab = "Distancia h",
     ylab = "Semivarianza γ(h)")

lines(modelo_esferico,   col = "#E41A1C", lwd = 2, lty = 1)
lines(modelo_exponencial, col = "#377EB8", lwd = 2, lty = 2)
lines(modelo_gaussiano,  col = "#4DAF4A", lwd = 2, lty = 3)

legend("bottomright",
       legend = c("Esférico", "Exponencial", "Gaussiano"),
       col    = c("#E41A1C", "#377EB8", "#4DAF4A"),
       lwd    = 2,
       lty    = c(1, 2, 3),
       bty    = "n",
       cex    = 0.95)

La Figura 8 permite comparar visualmente el ajuste de los tres modelos teóricos al semivariograma experimental. El modelo esférico y el modelo exponencial presentan mayores diferencias frente a los puntos observados, especialmente en las distancias intermedias y finales.

El modelo gaussiano presenta el comportamiento más consistente con la estructura observada del semivariograma, ya que acompaña mejor la forma suave y progresiva de la semivarianza. Esta lectura visual es coherente con el criterio numérico, pues el modelo gaussiano obtuvo la menor suma de cuadrados ponderada.

9.6 Tabla comparativa de parámetros y errores

# Extraer parámetros y errores de los tres modelos
tabla_modelos <- data.frame(
  Modelo     = c("Esférico", "Exponencial", "Gaussiano"),
  Nugget     = round(c(modelo_esferico$nugget,
                       modelo_exponencial$nugget,
                       modelo_gaussiano$nugget), 5),
  Sill       = round(c(modelo_esferico$cov.pars[1],
                       modelo_exponencial$cov.pars[1],
                       modelo_gaussiano$cov.pars[1]), 5),
  Range      = round(c(modelo_esferico$cov.pars[2],
                       modelo_exponencial$cov.pars[2],
                       modelo_gaussiano$cov.pars[2]), 6),
  SumaCuadrados = round(c(modelo_esferico$value,
                          modelo_exponencial$value,
                          modelo_gaussiano$value), 5)
)

kable(tabla_modelos,
      caption = "Tabla 2. Parámetros y error de ajuste de los modelos teóricos") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE) %>%
  row_spec(which.min(tabla_modelos$SumaCuadrados),
           bold = TRUE, background = "#d4edda")
Tabla 2. Parámetros y error de ajuste de los modelos teóricos
Modelo Nugget Sill Range SumaCuadrados
Esférico 1.01210 3.13670 0.001321 29339.172
Exponencial 1.01210 3.13670 0.000849 35114.968
Gaussiano 2.64595 3.50773 0.001668 8942.068

Aplicando los criterios de selección a los resultados obtenidos:

1. Suma de cuadrados: El modelo gaussiano obtiene el menor error de ajuste (8942.068), seguido por el modelo esférico (29339.172) y el modelo exponencial (35114.968). Por este criterio, el modelo gaussiano es el ganador.

2. Ajuste visual: El modelo gaussiano representa de manera más adecuada la forma suave y progresiva del semivariograma experimental, especialmente después de haber incorporado la tendencia espacial de primer orden.

3. Coherencia geoestadística: Los parámetros estimados para el modelo gaussiano son positivos y coherentes: nugget = 2.64595, sill = 3.50773 y range = 0.001668 grados. Aunque el nugget es relativamente alto, el modelo conserva estructura espacial suficiente para realizar la predicción mediante kriging.

Decisión final: Se selecciona el modelo gaussiano como el más adecuado para este conjunto de datos, debido a que presentó la menor suma de cuadrados ponderada y un comportamiento coherente con la variación espacial suave de la temperatura. En la siguiente sección se aplicará Kriging Universal usando el modelo gaussiano seleccionado.


10 Prediccion Espacial: Kriging Universal

La prueba de tendencia confirmó que ambas coordenadas son significativas, por lo que se aplica Kriging Universal con el modelo gaussiano seleccionado. Este modelo fue elegido porque obtuvo la menor suma de cuadrados ponderada en el ajuste del semivariograma y representa de forma adecuada la estructura espacial suave de la temperatura.

10.1 Construccion de la grilla de prediccion

x_min <- min(geo_datos$Longitude)
x_max <- max(geo_datos$Longitude)
y_min <- min(geo_datos$Latitude)
y_max <- max(geo_datos$Latitude)

cat("Longitud:", round(x_min, 6), "a", round(x_max, 6), "\n")
## Longitud: -76.7118 a -76.71022
cat("Latitud: ", round(y_min, 6), "a", round(y_max, 6), "\n")
## Latitud:  2.392101 a 2.393634
grilla <- expand.grid(
  Longitude = seq(x_min, x_max, length.out = 50),
  Latitude  = seq(y_min, y_max, length.out = 50)
)

cat("Nodos en la grilla:", nrow(grilla), "\n")
## Nodos en la grilla: 2500

10.2 Aplicacion del Kriging Universal

mejor_modelo <- modelo_gaussiano

kriging_resultado <- krige.conv(
  geodata   = geo_temp,
  locations = as.matrix(grilla),
  krige     = krige.control(
    obj.model = mejor_modelo,
    trend.d   = "1st",
    trend.l   = "1st"
  )
)
## krige.conv: model with mean given by a 1st order polynomial on the coordinates
## krige.conv: Kriging performed using global neighbourhood
cat("Número de predicciones:", length(kriging_resultado$predict), "\n")
## Número de predicciones: 2500
cat("\nTemperatura predicha:\n")
## 
## Temperatura predicha:
print(summary(kriging_resultado$predict))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   25.13   25.52   25.99   26.17   26.65   28.64
cat("\nVarianza de predicción:\n")
## 
## Varianza de predicción:
print(summary(kriging_resultado$krige.var))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   2.660   2.666   2.689   2.734   2.745   3.505

El Kriging Universal genero 2.500 predicciones sobre la grilla de la finca. La temperatura predicha oscila entre 24.10 y 28.38 grados C, con una media de 26.19 grados C, valores coherentes con el rango observado en los datos originales (22.2 a 29.7 grados C).

La varianza de prediccion va de 2.315 a 3.730, con una media de 2.539. Estos valores indican una incertidumbre moderada y uniforme en toda la grilla, lo que es esperable dado que los 534 arboles cubren el area de forma relativamente homogenea. Las zonas con mayor varianza (hasta 3.730) corresponden a los bordes de la finca donde hay menos puntos de muestreo cercanos.

10.3 Preparacion de los datos del mapa

mapa_datos <- data.frame(
  Longitude        = grilla$Longitude,
  Latitude         = grilla$Latitude,
  Temperatura_pred = kriging_resultado$predict,
  Varianza_kriging = kriging_resultado$krige.var
)

cat("Rango temperatura predicha:",
    round(min(mapa_datos$Temperatura_pred), 2), "a",
    round(max(mapa_datos$Temperatura_pred), 2), "grados C\n")
## Rango temperatura predicha: 25.13 a 28.64 grados C

11 Mapa Final de Prediccion Espacial

11.1 Mapa de temperatura interpolada

ggplot(mapa_datos, aes(x = Longitude, y = Latitude, fill = Temperatura_pred)) +
  geom_raster(interpolate = TRUE) +
  scale_fill_viridis_c(option = "plasma", name = "Temp C") +
  geom_point(data = geo_datos, aes(x = Longitude, y = Latitude),
             color = "white", size = 0.8, alpha = 0.5, inherit.aes = FALSE) +
  labs(title = "Figura 9. Mapa de temperatura - Kriging Universal",
       x = "Longitud", y = "Latitud") +
  theme_minimal(base_size = 13) +
  coord_fixed()

El mapa de interpolacion espacial revela un patron termico muy claro dentro de la finca. Las zonas con mayor temperatura (amarillo/naranja, 27-28 grados C) se concentran en el sector suroccidental y oriental, mientras que las temperaturas mas bajas (azul/morado, 24-25 grados C) dominan una franja diagonal que cruza la finca de noroeste a sureste.

Este gradiente diagonal coincide exactamente con el patron observado en la Figura 4 (mapa exploratorio inicial) y en los paneles del objeto geodata (Figura 5), lo que confirma que el Kriging Universal capturo correctamente la estructura espacial de la temperatura. La tendencia lineal bidireccional identificada en la Seccion 7 queda visualmente representada en este gradiente continuo.

Los puntos blancos muestran las ubicaciones reales de los 534 arboles. Se observa que la prediccion es coherente con los valores medidos, sin saltos bruscos entre puntos cercanos, lo que es una senal de buen ajuste del modelo geoestadistico.

11.2 Mapa de varianza del Kriging

ggplot(mapa_datos, aes(x = Longitude, y = Latitude,
                       fill = Varianza_kriging)) +
  geom_raster(interpolate = TRUE) +
  scale_fill_distiller(
    palette   = "YlOrRd",
    direction = 1,
    name      = "Varianza"
  ) +
  geom_point(
    data        = geo_datos,
    aes(x = Longitude, y = Latitude),
    color       = "black",
    size        = 0.7,
    alpha       = 0.4,
    inherit.aes = FALSE
  ) +
  labs(
    title    = "Figura 10. Mapa de varianza del Kriging",
    subtitle = "Incertidumbre de prediccion - 01/10/2020",
    x        = "Longitud",
    y        = "Latitud",
    caption  = "Menor varianza = mayor confianza en la prediccion"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title    = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(color = "gray40")
  ) +
  coord_fixed()

El mapa de varianza confirma un patron esperado en el Kriging: la incertidumbre es minima en el interior de la finca (amarillo claro, varianza ~2.3-2.4) donde hay alta densidad de puntos de muestreo, y maxima en las esquinas y bordes del area de prediccion (rojo, varianza ~3.6-3.7) donde no hay arboles muestreados.

El patron es simetrico desde el centro hacia las esquinas, lo que indica que la grilla de prediccion se extiende ligeramente mas alla del area cultivada. Las esquinas noreste y sureste muestran la mayor incertidumbre, lo que es coherente con la forma irregular de la finca observada en la Figura 3.

Este mapa tiene utilidad practica directa: si se quisiera ampliar el monitoreo de temperatura, los nuevos sensores deberian instalarse prioritariamente en los bordes norte y esquinas de la finca, que son las zonas con mayor varianza y menor confianza en la prediccion actual.


12 Interpretacion General de Resultados

La aplicacion del analisis geoestadistico a la temperatura del 01/10/2020 en la finca de aguacate del Cauca permitio los siguientes hallazgos:

  1. Variabilidad espacial confirmada: La temperatura varia entre 22.2 y 29.7 grados C dentro de la finca, con un CV de 6.86%. Aunque bajo en terminos relativos, esta variacion esta espacialmente organizada en un gradiente diagonal claro, lo que la hace analizable mediante geoestadistica.

  2. Tendencia espacial bidireccional: La prueba de regresion confirmo tendencia lineal significativa en ambas coordenadas (Longitud p = 0.00113, Latitud p = 0.000882), lo que justifico el uso de Kriging Universal en lugar de Kriging Ordinario.

  3. Autocorrelacion espacial presente: El semivariograma experimental mostro crecimiento monotonico desde nugget = 1.0 hasta una meseta de ~3.3-3.5, con rango aproximado de 89 metros. Esto confirma que arboles cercanos comparten condiciones termicas similares.

  4. Modelo gaussiano seleccionado: De los tres modelos ajustados, el gaussiano obtuvo la menor suma de cuadrados (8942.068), con nugget = 2.64595, sill = 3.50773 y range = 0.001668 grados. Esto indica que el modelo gaussiano representa de mejor manera la estructura espacial suave de la temperatura para la fecha analizada.

  5. Mapa de prediccion generado: El Kriging Universal produjo una superficie continua de temperatura con predicciones entre 24.10 y 28.38 grados C, revelando un gradiente termico diagonal que divide la finca en zonas calidas al suroccidente y frias al centro-nororiente.


13 Conclusiones

  1. El analisis geoestadistico es valido y aplicable: La temperatura del 01/10/2020 en la finca de aguacate presenta autocorrelacion espacial confirmada por el semivariograma experimental, lo que justifica el uso de Kriging Universal como un método adecuado de interpolación, ya que incorpora tanto la tendencia espacial como la estructura de autocorrelación estimada mediante el semivariograma.

  2. Existe un gradiente termico diagonal dentro de la finca: Las zonas de mayor temperatura (27-28 grados C) se ubican en el sector suroccidental y oriental, mientras que las temperaturas mas bajas (24-25 grados C) dominan una franja central de direccion noroeste-sureste. Este patron es claro para la fecha analizada y sugiere una estructura espacial no aleatoria.

  3. El modelo gaussiano es el más adecuado: Con la menor suma de cuadrados ponderada (8942.068), el modelo gaussiano fue seleccionado como el modelo teórico más apropiado para representar la autocorrelación espacial de la temperatura. Sus parámetros permiten describir una variación térmica suave y continua dentro de la finca.

  4. El Kriging Universal mejora la prediccion al incorporar la tendencia: La tendencia lineal bidireccional significativa (p < 0.01 en ambas coordenadas) indica que el proceso no es estacionario. Al incorporarla explicitamente en el modelo, el Kriging Universal resulta metodológicamente más adecuado que el Kriging Ordinario para este conjunto de datos, porque incorpora explícitamente la tendencia espacial detectada en las coordenadas.

  5. El mapa de varianza orienta decisiones de monitoreo: Las zonas de mayor incertidumbre (bordes y esquinas de la finca, varianza hasta 3.73) indican donde instalar nuevos sensores para mejorar la cobertura espacial del monitoreo termico. El interior de la finca tiene alta confianza en la prediccion (varianza ~2.3).

  6. Limitacion temporal: El analisis corresponde a un unico dia de muestreo (01/10/2020). Para determinar si el gradiente termico es estable a lo largo del ciclo productivo, seria necesario repetir el analisis en otras fechas y comparar los patrones espaciales obtenidos.