A partir de la base de datos “Datos_Completos_Aguacate.xlsx” que contiene información sobre las variables climatológicas y de terreno de una finca en el departamento de Cauca (Colombia), tomando como filtro únicamente el periodo “01/10/2020 10:11:12 a, m,” y usando la variable “Temperature”, se debe realizar el análisis geoestadístico, siguiendo los pasos:
Si en algún evento la variable “Temperature” no tiene una autocorrelación espacial siginificativa, se puede seleccionar otra variable para realizar el desarrollo de la actividad (pueden ser “Relative_Humidity”, “Wind_Speed”, “Altitude”).
Antes de desarrollar los puntos, realizamos un análisis exploratorio para limpiar la base de datos de datos faltantes y posibles inconsistencias, observemos que tipo de variables disponemos.
# Importar base de datos solicitada
FincaAguacate_Excel <- "C:/Users/Christian/Desktop/Carpeta del Todo/Cursos Maestria en Ciencia de Datos/07 - Analisis de datos geograficos y espaciales/Unidad 2.1 - Exploracion de datos con Geoestadistica/Datos_Completos_Aguacate.xlsx"
FincaAguacate= suppressMessages(suppressWarnings(read_excel(FincaAguacate_Excel)))
#Base de datos solicitada para este trabajo
str(FincaAguacate, vec.len = 2, give.attr = FALSE)
## tibble [20,271 × 21] (S3: tbl_df/tbl/data.frame)
## $ id_arbol : chr [1:20271] "1" "2" ...
## $ Latitude : num [1:20271] 2.38 2.38 ...
## $ Longitude : num [1:20271] -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," ...
## $ Psychro_Wet_Bulb_Temperature : num [1:20271] 14.8 11.6 12.9 14.1 14.3 ...
## $ Station_Pressure : num [1:20271] 805 805 ...
## $ Relative_Humidity : num [1:20271] 33.6 36.8 31.5 33.2 34.3 ...
## $ Crosswind : num [1:20271] 0.2 3.6 0.4 0.6 0.4 ...
## $ Temperature : num [1:20271] 25.7 20.8 23.7 25 25 ...
## $ Barometric_Pressure : num [1:20271] 805 805 ...
## $ Headwind : num [1:20271] 0.7 3.5 0.7 0.7 0.4 ...
## $ Direction_True : num [1:20271] 166 314 332 139 129 ...
## $ Direction_Mag : num [1:20271] 165 313 331 139 128 ...
## $ Wind_Speed : num [1:20271] 0.8 5.1 0.8 0.9 0.6 ...
## $ Heat_Stress_Index : num [1:20271] 24.1 19.5 22 23.2 23.3 ...
## $ Altitude : num [1:20271] 1896 1895 ...
## $ Dew_Point : num [1:20271] 8.6 5.5 5.8 7.7 8.1 ...
## $ Density_Altitude : num [1:20271] 2.74 2.57 ...
## $ Wind_Chill : num [1:20271] 25.7 20.8 23.7 24.9 24.9 ...
## $ Estado_Fenologico_Predominante: num [1:20271] 715 715 715 715 715 ...
## $ Frutos_Afectados : num [1:20271] 0 3 0 0 1 ...
Iniciamos con una revisión de los datos faltantes. Dado que para esta actividad solo nos interesa los datos de ubicación (“Latitude” y “Longitude”), la fecha (“FORMATTED_DATE_TIME”) para poder realizar el filtro, y temperatura “Temperature”, solo se realizará el análisis para estas variables.
#Calculando datos faltantes
Datos_faltantes <- data.frame(colnames(FincaAguacate), sapply(FincaAguacate, function(x) sum(is.na(x))))
Datos_faltantes <- Datos_faltantes[c(2:4, 9), ]
#Limpiando Dataframe
rownames(Datos_faltantes) <- NULL
colnames(Datos_faltantes) <- c("Variable", "Datos Faltantes")
#Presentando información en formato tabla
kable_classic(kbl(Datos_faltantes, caption = "<center><b>Tabla 1. Datos Faltantes por Variable</b></center>"), full_width = F)
| Variable | Datos Faltantes |
|---|---|
| Latitude | 0 |
| Longitude | 0 |
| FORMATTED_DATE_TIME | 0 |
| Temperature | 0 |
Vemos que ninguna de las variables evaluadas presenta datos faltantes.
# Filtramos la cadena de texto solicitada
FincaAguacate_Filtro <- FincaAguacate[FincaAguacate$FORMATTED_DATE_TIME == "01/10/2020 10:11:12 a, m,",]
print(FincaAguacate_Filtro)
## # A tibble: 0 × 21
## # ℹ 21 variables: id_arbol <chr>, Latitude <dbl>, Longitude <dbl>,
## # FORMATTED_DATE_TIME <chr>, Psychro_Wet_Bulb_Temperature <dbl>,
## # Station_Pressure <dbl>, Relative_Humidity <dbl>, Crosswind <dbl>,
## # Temperature <dbl>, Barometric_Pressure <dbl>, Headwind <dbl>,
## # Direction_True <dbl>, Direction_Mag <dbl>, Wind_Speed <dbl>,
## # Heat_Stress_Index <dbl>, Altitude <dbl>, Dew_Point <dbl>,
## # Density_Altitude <dbl>, Wind_Chill <dbl>, …
# Encontramos registros que contengan el dato
print(head(FincaAguacate[grepl(
"01/10/2020",FincaAguacate$FORMATTED_DATE_TIME), ][c(1:4)], 5))
## # A tibble: 5 × 4
## id_arbol Latitude Longitude FORMATTED_DATE_TIME
## <chr> <dbl> <dbl> <chr>
## 1 1 2.39 -76.7 01/10/2020 10:11:12 a, m,
## 2 2 2.39 -76.7 01/10/2020 10:11:12 a, m,
## 3 3 2.39 -76.7 01/10/2020 10:11:12 a, m,
## 4 4 2.39 -76.7 01/10/2020 10:11:12 a, m,
## 5 5 2.39 -76.7 01/10/2020 10:11:12 a, m,
# Verificamos los valores hexadecimales de ambas cadenas de texto
charToRaw(FincaAguacate$FORMATTED_DATE_TIME[9140])
## [1] 30 31 2f 31 30 2f 32 30 32 30 c2 a0 20 31 30 3a 31 31 3a 31 32 20 61 2c 20
## [26] 6d 2c
charToRaw("01/10/2020 10:11:12 a, m,")
## [1] 30 31 2f 31 30 2f 32 30 32 30 20 20 31 30 3a 31 31 3a 31 32 20 61 2c 20 6d
## [26] 2c
# Eliminar espacios no quiebre
FincaAguacate_fix <- FincaAguacate
FincaAguacate_fix$FORMATTED_DATE_TIME <- gsub(
"\u00A0", " ", FincaAguacate_fix$FORMATTED_DATE_TIME)
# Filtramos nuevamente la cadena de texto solicitada
FincaAguacate_Filtro <- FincaAguacate_fix[
FincaAguacate_fix$FORMATTED_DATE_TIME == "01/10/2020 10:11:12 a, m,",]
print(FincaAguacate_Filtro)
## # A tibble: 534 × 21
## id_arbol Latitude Longitude FORMATTED_DATE_TIME Psychro_Wet_Bulb_Tem…¹
## <chr> <dbl> <dbl> <chr> <dbl>
## 1 1 2.39 -76.7 01/10/2020 10:11:12 a, m, 22
## 2 2 2.39 -76.7 01/10/2020 10:11:12 a, m, 21.4
## 3 3 2.39 -76.7 01/10/2020 10:11:12 a, m, 21.8
## 4 4 2.39 -76.7 01/10/2020 10:11:12 a, m, 22.8
## 5 5 2.39 -76.7 01/10/2020 10:11:12 a, m, 22.6
## 6 6 2.39 -76.7 01/10/2020 10:11:12 a, m, 21.5
## 7 7 2.39 -76.7 01/10/2020 10:11:12 a, m, 22.2
## 8 8 2.39 -76.7 01/10/2020 10:11:12 a, m, 22.6
## 9 9 2.39 -76.7 01/10/2020 10:11:12 a, m, 23
## 10 10 2.39 -76.7 01/10/2020 10:11:12 a, m, 22.7
## # ℹ 524 more rows
## # ℹ abbreviated name: ¹Psychro_Wet_Bulb_Temperature
## # ℹ 16 more variables: Station_Pressure <dbl>, Relative_Humidity <dbl>,
## # Crosswind <dbl>, Temperature <dbl>, Barometric_Pressure <dbl>,
## # Headwind <dbl>, Direction_True <dbl>, Direction_Mag <dbl>,
## # Wind_Speed <dbl>, Heat_Stress_Index <dbl>, Altitude <dbl>, Dew_Point <dbl>,
## # Density_Altitude <dbl>, Wind_Chill <dbl>, …
# Convertir dataframe en geodata
FincaAguacate_geo <- as.geodata(
FincaAguacate_Filtro,coords.col = 3:2,data.col = 9)
# Gráficar geodata
par(mfrow = c(2, 1), mar = c(0, 4, 0, 4))
plot.new()
text(x = 0.5, y = 0.5, labels = "Gráfico 1. Objeto geodata de la\nvariable Temperatura",
cex = 1.7)
plot(FincaAguacate_geo)
# Calculamos las estadísticas de los puntos de estudio
summary(dist(FincaAguacate_Filtro[3:2]))
## 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 variograma
FincaAguacate_variog <- variog(FincaAguacate_geo,option = "bin",
uvec=seq(0,9.178e-04,9.178e-05), messages = FALSE)
# Calcular margen de correlación
FincaAguacate_marks <- variog.mc.env(FincaAguacate_geo,
obj=FincaAguacate_variog, messages = FALSE)
# Graficar semivariograma
plot(FincaAguacate_variog, main = "Gráfico 2. Semivariograma de Temperatura",
xlab = "Distancia", ylab = "Semivarianza")
lines(FincaAguacate_marks)
# Humedad relativa
# Convertir dataframe en geodata
FincaAguacate_geo2 <- as.geodata(
FincaAguacate_Filtro,coords.col = 3:2,data.col = 7)
# Crear variograma
FincaAguacate_variog2 <- variog(FincaAguacate_geo2,option = "bin",
uvec=seq(0,9.178e-04,9.178e-05), messages = FALSE)
# Calcular margen de correlación
FincaAguacate_marks2 <- variog.mc.env(FincaAguacate_geo2,
obj=FincaAguacate_variog2, messages = FALSE)
# Graficar semivariograma
plot(FincaAguacate_variog2, main = "Gráfico 3. Semivariograma de Humedad Relativa",
xlab = "Distancia", ylab = "Semivarianza")
lines(FincaAguacate_marks2)
# Velocidad del viento
# Convertir dataframe en geodata
FincaAguacate_geo2 <- as.geodata(
FincaAguacate_Filtro,coords.col = 3:2,data.col = 14)
# Crear variograma
FincaAguacate_variog2 <- variog(FincaAguacate_geo2,option = "bin",
uvec=seq(0,9.178e-04,9.178e-05), messages = FALSE)
# Calcular margen de correlación
FincaAguacate_marks2 <- variog.mc.env(FincaAguacate_geo2,
obj=FincaAguacate_variog2, messages = FALSE)
# Graficar semivariograma
plot(FincaAguacate_variog2, main = "Gráfico 4. Semivariograma de Velocidad del Viento",
xlab = "Distancia", ylab = "Semivarianza")
lines(FincaAguacate_marks2)
# Altitud
# Convertir dataframe en geodata
FincaAguacate_geo2 <- as.geodata(
FincaAguacate_Filtro,coords.col = 3:2,data.col = 16)
# Crear variograma
FincaAguacate_variog2 <- variog(FincaAguacate_geo2,option = "bin",
uvec=seq(0,9.178e-04,9.178e-05), messages = FALSE)
# Calcular margen de correlación
FincaAguacate_marks2 <- variog.mc.env(FincaAguacate_geo2,
obj=FincaAguacate_variog2, messages = FALSE)
# Graficar semivariograma
plot(FincaAguacate_variog2, main = "Gráfico 5. Semivariograma de Altitud",
xlab = "Distancia", ylab = "Semivarianza")
lines(FincaAguacate_marks2)
#Fijar rango de evaluación
val_ini <- expand.grid(seq(1.5,3,l=10), seq(4e-04,6e-04,l=10))
# Gráficar semiovariograma junto a las curvas teóricas
plot(FincaAguacate_variog, main = "Gráfico 6. Semivariograma de Temperatura\ncon modelos teóricos",
xlab = "Distancia", ylab = "Semivarianza")
FincaAguacate_exp <- variofit(FincaAguacate_variog, ini=val_ini,
cov.model="exponential", wei="npair",
min="optim", messages = FALSE)
FincaAguacate_gaus <- variofit(FincaAguacate_variog, ini=val_ini,
cov.model="gaussian", wei="npair",
min="optim",nugget = 0, messages = FALSE)
FincaAguacate_spe <- variofit(FincaAguacate_variog, ini=val_ini,
cov.model="spheric",fix.nug=TRUE,
wei="npair", min="optim", messages = FALSE)
lines(FincaAguacate_exp,col="blue")
lines(FincaAguacate_gaus,col="red")
lines(FincaAguacate_spe,col="yellow")
#Crear dataframe de la summa de errores cuadrados por modelo
Errores_cuadrado <- data.frame(Modelo=c("Exponencial", "Gaussiano", "Esférico"),
Suma_Errores=c(FincaAguacate_exp$value, FincaAguacate_gaus$value, FincaAguacate_spe$value))
#Crear tabla para visualizar la suma de errores cuadrados
kbl(Errores_cuadrado, caption = "<center><b>Tabla 2. Suma de Errores al cuadrado por Modelo</b></center>", col.names=c("Modelo","Suma de errores al cuadrado"))%>%
kable_classic(full_width = F)
| Modelo | Suma de errores al cuadrado |
|---|---|
| Exponencial | 4857.673 |
| Gaussiano | 14947.769 |
| Esférico | 6583.649 |
#Crear dataframe del área a gráficar
area_val <- data.frame(Modelo=c("Min. Long", "Max Long.", "Min. Lat", "Max. Lat"),
Suma_Errores=c(min(FincaAguacate_Filtro[3]), max(FincaAguacate_Filtro[3]), min(FincaAguacate_Filtro[2]), max(FincaAguacate_Filtro[2])))
#Crear tabla para visualizar los valores del área
kbl(area_val, caption = "<center><b>Tabla 3. Rango de área a graficar</b></center>", col.names=c("Línea","Valor"))%>%
kable_classic(full_width = F)
| Línea | Valor |
|---|---|
| Min. Long | -76.711799 |
| Max Long. | -76.710215 |
| Min. Lat | 2.392101 |
| Max. Lat | 2.393634 |
# Graficar grilla de terreno
FincaAguacate_grilla <- expand.grid(lon=seq(-76.7118, -76.71022, l=100),
lat=seq(2.392101, 2.393634, l=100))
plot(FincaAguacate_grilla, main = "Gráfico 7. Grilla del terreno",
xlab = "Longitud", ylab = "Latitud")
points(FincaAguacate_Filtro[3:2],col="yellow")
# Crear predicción, pasando modelo
salida <- output.control(messages=FALSE)
FincaAguacate_pred <- krige.conv(
FincaAguacate_geo, loc=FincaAguacate_grilla, output = salida,
krige= krige.control(obj.model = FincaAguacate_exp))
# Gráficar predicción
par(mfrow=c(1,2))
image(FincaAguacate_pred, main="Gráfico 8. Predicción Espacial",
xlab="Longitud", ylab="Latitud")
par(new=TRUE)
contour(FincaAguacate_pred, xlab="Longitud", ylab="Latitud", drawlabels=TRUE)
# Gráficar desviación del error predicción
par(mfrow=c(1,2))
image(FincaAguacate_pred, main="Gráfico 9. Error de la Predicción\nEspacial",
val=sqrt(FincaAguacate_pred$krige.var), xlab="Longitud", ylab="Latitud")
par(new=TRUE)
contour(FincaAguacate_pred, xlab="Longitud",
val=sqrt(FincaAguacate_pred$krige.var), ylab="Latitud", drawlabels=TRUE)
# Creando mapa raster a partir de los datos
FincaAguacate_tempPred <- rasterFromXYZ(cbind(FincaAguacate_grilla, FincaAguacate_pred$predict))
plot(FincaAguacate_tempPred, main="Gráfico 10. Mapa raster de temperatura",
xlab="Longitud", ylab="Latitud")
# Creando mapa raster del error a partir de los datos
FincaAguacate_errorPred <- rasterFromXYZ(cbind(FincaAguacate_grilla, val=sqrt(FincaAguacate_pred$krige.var)))
plot(FincaAguacate_errorPred, main="Gráfico 11. Mapa raster del error de la predicción",
xlab="Longitud", ylab="Latitud")
FincaAguacate_valid=xvalid(geodata = FincaAguacate_geo,
model = FincaAguacate_exp)
## xvalid: number of data locations = 534
## xvalid: number of validation locations = 534
## xvalid: performing cross-validation at location ... 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534,
## xvalid: end of cross-validation
MAE=mean(abs(FincaAguacate_valid$error))
print(MAE)
## [1] 0.7909316