El clima de Australia varía ampliamente, aunque la mayor parte de Australia es desértico o semiárido, el 40% del territorio está cubierto por médanos. Solo las esquinas sudestes y sudoestes tienen un clima templado y de suelos moderadamente fértiles. La parte norte del país tiene un clima tropical: parte es bosque lluvioso tropical, parte pastizales, y parte desiertos.
El gran objetivo de este trabajo, es analizar la variable climatológica de temperatura en un enfoque geoestadístico, centrándonos en el perímetro del territorio australiano, el cual es bastante diverso en éste ámbito de estudio.
Las temperaturas más calientes australianas pueden alcanzar los 50 °C, mientras las mínimas pueden bajar de cero. El continente no tiene grandes variaciones en altitud y está rodeado mayormente por océanos templados. Así resulta que son extremadamente infrecuentes las bajas temperaturas. Consecuentemente, Australia es un país tan grande que goza de muchas condiciones climáticas: desde el calor del desierto hasta las bajas temperaturas nevadas de las montañas; desde las abundantes lluvias hasta la ausencia total de precipitaciones.
Por estas razones, es de gran interés realizar un análisis geoestadístico de la temperatura, con el fin de pensar que tan correlacionadas se pueden encontrar los valores de temperatura medidos y si es posible ajustar un modelo con el fin de llegar a posibles predicciones para la variable de interés en sitios no muestreados.
Este conjunto de datos presenta las locaciones de puntos muestreados en diferentes zonas de Australia, donde se toman valores de temperatura máxima diaria promedio, elevación y coordenadas de georeferenciación en latitud - longitud.
los datos fueron extraídos de la página de Kaggle, la cual es una plataforma web que reune a la comunidad de ciencia de datos más grande del mundo, con más de 536 mil miembros activos en 194 países Temperarura_Australia.
Las variables que se tienen en cuenta para el estudio son las siguientes:
| Variable | Descripción | Tipo | Detalle |
|---|---|---|---|
| X | Código del registro | integer | - |
| lat | Coordenadas latitud | float | - |
| long | Coordenadas longitud | float | - |
| elev | Elevación de la zona | float | - |
| name | ciudad-pueblo donde se registró la temperatura | string | - |
| Year | Año en que se tomaron los datos | interger | - |
| Temp | Valor de temperatura tomado (grados celcius) | float | - |
#Lectura librerías
library(leaflet)
library(dplyr)
library(ggplot2)
library(geoR)
library(sf)
library(rgdal)
library(readxl)
library(raster)
library(readr)
library(kableExtra)
library(ade4)
library(vegan)
library(gstat)
library(sp)#Lectura Datos
temper <- read.csv("temp.australia.csv")
head(temper)temper$lat <- as.numeric(temper$lat)
temper$long <- as.numeric(temper$long)class(temper$lat)## [1] "numeric"
class(temper$long)## [1] "numeric"
mapa_aus <- leaflet() %>%
addProviderTiles(providers$Esri.NatGeoWorldMap)
mapa_aus %>%
addMarkers(lat=~lat, lng =~long, data = temper,
icon = makeIcon(iconUrl = "temper2.png",
iconWidth = 20, iconHeight = 20),
popup = paste(
"<h3>Registro climatológico</h3>",
paste("Temperatura:",
round(temper$Temp, 2)),
paste("Elevación:",
round(temper$elev), 2),
sep = "<br>"
)
)Análisis descriptivo
ggplot(temper,aes(x=long,y=lat,color=Temp))+geom_point()+theme_bw()+
scale_color_continuous(type = "viridis")Se puede notar que las temperaturas bajas son muy frecuentadas en la zona sur de Australia y en el norte las temperaturas más cálidas, lo cual puede tener una relación muy significativa con la cercanía a la Antártida.
Datos en formato geoR
# Covertir datos en formato geoR
geodatoslatlong <- as.geodata(temper,coords.col=3:2,data.col=7)
class(geodatoslatlong)## [1] "geodata"
plot(geodatoslatlong,lowess=TRUE)gr <- pred_grid(geodatoslatlong$coords, by=20)
points(geodatoslatlong)
points(gr, col=7, pch=19, cex=0.3)
gr0 <- gr[.geoR_inout(gr, geodatoslatlong$coords),]
points(gr0, col=7, pch=19, cex=0.3)Shapefile Australia
austr <- shapefile("AUS_2021_AUST_GDA2020.shp")
class(austr)## [1] "SpatialPolygonsDataFrame"
## attr(,"package")
## [1] "sp"
austr## class : SpatialPolygonsDataFrame
## features : 1
## extent : 96.81695, 167.998, -43.7405, -9.142163 (xmin, xmax, ymin, ymax)
## crs : +proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs
## variables : 6
## names : AUS_CODE21, AUS_NAME21, CHG_FLAG21, CHG_LBL21, AREASQKM21, LOCI_URI21
## value : AUS, Australia, 0, No change, 7688094.9379, http://linked.data.gov.au/dataset/asgsed3/AUS/AUS
Geometría Australia
croq <- geometry(austr)
plot(croq)Para realizar el test, claramente se deben proyectar los puntos muestreados a UTM, con el fin de llevar las geolocalizaciones al plano, para ésto, se crea una variable llamada zona, la cual especifica la zona en mercator para cada uno de los puntos muestreados. Posteriormente, se genera una función que utiliza a spTransform de la librería rgdal y recorre cada una de las zonas y las coordenadas latitud - longitud para adicionar a los datos las columnas de coordenadas UTM para cada uno de los puntos.
Para la conversión a UTM, Australia cuenta con múltiples zonas de mercator, por ende, se genera una función que recorre las zonas y transforma dichas coordenadas de latitud - longitud a UTM.
Al transformar las coordenadas a UTM, se obtienen valores en metros, pero dado el tamaño de Australia, se decide convertir dichas métricas a kilómetros.
Transformación coordenadas a UTM
get_utm <- function(long, lat, zone, loc){
points = SpatialPoints(cbind(long, lat), proj4string = CRS("+proj=longlat +datum=WGS84"))
points_utm = spTransform(points, CRS(paste0("+proj=utm +south=T +zone=",zone[1]," +ellps=WGS84")))
if (loc == "long") {
return(coordinates(points_utm)[,1])
} else if (loc == "lat") {
return(coordinates(points_utm)[,2])
}
}
temper %<>%
mutate(zone = (floor((long + 180)/6) %% 60) + 1, keep = "all"
) %>%
group_by(zone) %>%
mutate(utm_x = get_utm(long, lat, zone, loc = "long"),
utm_y = get_utm(long, lat, zone, loc = "lat"))
temper$utm_x <- temper$utm_x/1000
temper$utm_y <- temper$utm_y/1000Datos finales
head(temper)plot(temper$utm_x,temper$utm_y,ylab="UTM Y",xlab="UTM X")Se genera Matriz de distancias espaciales entre los lugaes de muestreo
# Matriz de distancias espaciales entre los lugaes de muestreo
geodist <- dist(temper[,11:10], diag=TRUE, upper=TRUE)Matriz de distancias entre las observaciones registradas en los lugares de muestreo de temperatura
# Matriz de distancias entre las observacioens registradas
# en los lugares de muestreo de temperatura
dist.temp <- dist(temper[,7], diag=TRUE, upper=TRUE)^2Se genera un data frame para extraer los valores de las matrices, utilizando la fracción inferior lower
# Creamos un data frame para extraer los valores de las matrices, ya sea la fracción triangular superior o inferior (en este ejemplo, utilizaremos la inferior, es decir: lower)
df2 <- data.frame(Disimilitud=dist.temp[lower.tri(dist.temp)], Distancia=geodist[lower.tri(geodist)])Gráfico Disimilitud Vs Distancia geográfica (m)
plot <- ggplot(df2, aes(x=Distancia, y=Disimilitud)) + geom_point() +
theme_test(base_size = 14, base_family = "Times New Roman") +
labs(x="Distancia geográfica (km)", y="Disimilitud") +
theme(axis.title = element_text(face="bold"), axis.text = element_text(colour="black"))
plotGráfico Disimilitud Vs Distancia geográfica (m) con línea tendencia
plot2 <- ggplot(df2, aes(x=Distancia, y=Disimilitud)) +
geom_point() + theme_test(base_size = 14, base_family = "Times New Roman") +
labs(x="Distancia geográfica (km)", y="Disimilitud") +
theme(axis.title = element_text(face="bold"), axis.text = element_text(colour="black")) +
geom_smooth(method=lm)
plot2Test Mantel
mantel(geodist, dist.temp) # vegan##
## Mantel statistic based on Pearson's product-moment correlation
##
## Call:
## mantel(xdis = geodist, ydis = dist.temp)
##
## Mantel statistic r: 0.7665
## Significance: 0.001
##
## Upper quantiles of permutations (null model):
## 90% 95% 97.5% 99%
## 0.0556 0.0726 0.0842 0.1069
## Permutation: free
## Number of permutations: 999
Evidentemente se rechaza la hipótesis nula, lo que sugiere que si hay autocorrelación espacial en los datos.
Monte Carlo test
mantel.rtest(geodist, dist.temp, nrepet=999) # ade4## Monte-Carlo test
## Call: mantelnoneuclid(m1 = m1, m2 = m2, nrepet = nrepet)
##
## Observation: 0.7665377
##
## Based on 999 replicates
## Simulated p-value: 0.001
## Alternative hypothesis: greater
##
## Std.Obs Expectation Variance
## 1.857250e+01 -3.274998e-05 1.703583e-03
Con el test de Monte Carlo, se llega a la misma conclusión, que nos entrega evidencia estadística para quedarnos con auocorrelación espacial.
Datos UTM en formato geoR
# Covertir datos en formato geoR
geodatos <- as.geodata(temper,coords.col=10:11,data.col=7)
plot(geodatos,lowess=TRUE)Estos gráficos, entregan señales muy a favor de la autocorrelación espacial, en el primer gráfico superior izquierdo, se observan clusters y en el gráfico inferior izquierdo una clara tendencia positiva..
Resumen geodatos
summary(geodatos)## Number of data points: 111
##
## Coordinates summary
## utm_x utm_y
## min 187.4691 5184.758
## max 785.5417 8830.168
##
## Distance summary
## min max
## 8.032545 3647.691357
##
## Data summary
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 9.815563 20.176630 23.356290 23.928424 27.313460 34.336910
points(geodatos,col = "gray", pt.divide = "equal")Semivariograma muestral
# Semivariograma muestral
variograma <- variog(geodatos,option="bin",uvec=seq(0,3800,200))## variog: computing omnidirectional variogram
# Grafico del variograma muestral
plot(variograma)Destruyendo la correlación espacial a traves de permutaciones aleatorias
# Destruir la correlación espacial a traves de permutaciones aleatorias
geoP2 <- data.frame(geodatos$coords,sample(geodatos$data))
geodatosP2 <- as.geodata(geoP2,coords.col=1:2,data.col=3)
plot(geodatosP2)Semivariograma muestral
# Semivariograma muestral
variogramaP2 <- variog(geodatosP2,option = "bin",uvec=seq(0,3800,200))## variog: computing omnidirectional variogram
plot(variograma, col="2")
lines(variogramaP2,type="l")Bandas de confianza para test gráfico
plot(variograma)
variograma.emv=variog.mc.env(geodatos,obj=variograma)## variog.env: generating 99 simulations by permutating data values
## variog.env: computing the empirical variogram for the 99 simulations
## variog.env: computing the envelops
lines(variograma.emv,col="blue")El test gráfico manifiesta un comportamiento esperado, donde la mayoría de puntos caen fuera de las bandas, por lo cual, la variable Temperatura cuenta con autocorrelación espacial.
Considerando que ya se puede ajustar un posible modelo, pues la variable temperatura cuenta con las condiciones de correlación espacial, se procede a ajustar un modelo con el fin de realizar predicciones Kriging en locaciones no muestreadas de Australia.
Determinación de efectos direccionales - anisotropía
plot(variog4(geodatos, trend = "2nd", max.dist = 3647.69), omnidirectional = T)## variog: computing variogram for direction = 0 degrees (0 radians)
## tolerance angle = 22.5 degrees (0.393 radians)
## variog: computing variogram for direction = 45 degrees (0.785 radians)
## tolerance angle = 22.5 degrees (0.393 radians)
## variog: computing variogram for direction = 90 degrees (1.571 radians)
## tolerance angle = 22.5 degrees (0.393 radians)
## variog: computing variogram for direction = 135 degrees (2.356 radians)
## tolerance angle = 22.5 degrees (0.393 radians)
## variog: computing omnidirectional variogram
Como se puede observar en el grafico de semivariogramas direccionales, existe anisotropia la cual se da cuando la autocorrelación no es igual en todas las direcciones, en este caso es anisotropia zonal, ya que todos los semivariogramas tienen igual rango pero diferente meseta.
Ajustes
exp_fit_fix <- variofit(variograma, cov.model = "exp", fix.nugget = F)## 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 "108.95" "2880" "0" "0.5"
## status "est" "est" "est" "fix"
## loss value: 1145121.65594699
sph_fit_fix <- variofit(variograma, cov.model = "sph", fix.nugget = F)## 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 "72.63" "2880" "0" "0.5"
## status "est" "est" "est" "fix"
## loss value: 1101980.59861456
gauss_fit_fix <- variofit(variograma, cov.model = "gaussian", fix.nugget = F)## 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 "145.26" "2304" "0" "0.5"
## status "est" "est" "est" "fix"
## loss value: 51317.2341546973
Modelo gaussiano:Rojo
plot(variograma,pch=16)
lines(exp_fit_fix,col="green",lwd=4, lty = 1)
lines(sph_fit_fix,col="blue",lwd=4, lty = 3)
lines(gauss_fit_fix,col="red",lwd=4, lty = 4)
legend("topleft", c("Gauss","Expo","Spe"),
col = c("red","blue","green"), lwd = 1, cex = 0.5)Comparación del SSE de los modelos
Modelo exponencial
(exp_SSQ_fix <- summary(exp_fit_fix)$sum.of.squares)## value
## 520916.5
Modelo esférico
(sph_SSQ_fix <- summary(sph_fit_fix)$sum.of.squares)## value
## 520876.9
Modelo gaussiano
(gauss_SSQ_fix <- summary(gauss_fit_fix)$sum.of.squares)## value
## 11706.03
which.min(list(exp_SSQ_fix,
sph_SSQ_fix, gauss_SSQ_fix))## [1] 3
Creación de una grilla de predicción
#xmin:180 xmax: 800 ymin:5000 ymax:9000
prediction_grid <- expand.grid(seq(187.4691, 785.5417, length.out = 100), seq(5184.758, 8830.168, length.out = 100))
plot(prediction_grid)krig_temp <- krige.conv(geodatos, loc=prediction_grid,
krige=krige.control(obj.model=gauss_fit_fix))## krige.conv: model with constant mean
## krige.conv: Kriging performed using global neighbourhood
image(krig_temp,main="Predicción Modelo Gaussiano")
points(geodatos$coords, pch=20) #añadir posiciones datoscontour(krig_temp,add=TRUE,filled = TRUE) #añadir gráfico de contornovariogramas <- list()
bandas_conf <- list()
ini.vals <- expand.grid(seq(10, 40, l = 10), seq(50000, 150000, l = 10))
model_mco_exps <- list()
model_mco_gaus <- list()
model_mco_spes <- list()
for(i in 1:4){
variograma <- variog(geodatos, data = geodatos$data,
option = "bin",
uvec = seq(0, 3800, length.out = 20),
messages = F)
variogramas[[i]] <- variograma
## bandas de confianza, si hay o no autocorrelacion
variograma.emv <- variog.mc.env(geodatos, data = geodatos$data,
obj = variograma, messages = F)
bandas_conf[[i]] <- variograma.emv
model_mco_exps[[i]] <- variofit(variogramas[[i]], ini = ini.vals,
cov.model = "exponential",
wei = "npair", min = "optim", messages = F)
model_mco_gaus[[i]] <- variofit(variogramas[[i]], ini = ini.vals,
cov.model = "gaussian",
wei = "npair", min = "optim", nugget = 0, messages = F)
model_mco_spes[[i]] <- variofit(variogramas[[i]], ini = ini.vals,
cov.model = "spheric", fix.nug = TRUE,
wei = "npair", min = "optim", messages = F)
}Titulos <- c("Temperatura")
plot(variograma, envelope = bandas_conf[[i]],
pch = 19, las = 1, main = Titulos,
xlab = "Distancia (km)", ylab = "Semivarianza")
lines(model_mco_exps[[i]], col="blue")
lines(model_mco_gaus[[i]], col="red")
lines(model_mco_spes[[i]], col="green")
legend("topleft", c("Gauss","Expo","Spe"),
col = c("red","blue","green"), lwd = 1, cex = 0.5)Aqui podemos ratificar como el modelo gaussiano es el más optimo para la predicción, además de ser el que mejor se ajusta a los puntos del variograma, tambien verificamos que existe autocorrelación espacial a ver como los puntos del semivariograma se encuentran en su mayoria fuera de las bandas de confianza.
raster.ko <- list(map_image_gaus.ko, map_image_exps.ko, map_image_spes.ko)
vars.ko <- list(map_image_gausvar.ko, map_image_expsvar.ko, map_image_spesvar.ko)
nombres_modelos <- c("Modelo gaussiano", "Modelo exponencial",
"Modelo esférico")
modelos <- list(model_mco_gaus, model_mco_exps, model_mco_spes)
xvs <- c()
labels <- c()
maps.plot <- function(i, j, plot.var = F) {
#par(mfrow = c(1, 2))
label <- paste(Titulos[i], "\n",nombres_modelos[j])
if (!plot.var) {
plot(raster.ko[[j]][[i]],
main = paste(label, "(predicción)"), cex.main = 0.8,
col = viridis::inferno(20))
} else {
plot(vars.ko[[j]][[i]], main = paste(label, "(desviación estándar)"),
cex.main = 0.8, col = viridis::inferno(20))
}
xv <- xvalid(geodatos, data = geodatos$data,
model = modelos[[j]][[i]])$error^2
xvs <- append(xvs, mean(xv))
#labels <- append(labels, str_replace(label, " \\n ", " "))
}Modelo Gaussiano
maps.plot(1, 1)Desviación modelo Gaussiano
maps.plot(1, 1, T)Modelo exponencial
maps.plot(1, 2)Desviación modelo exponencial
maps.plot(1, 2, T)Modelo esférico
maps.plot(1, 3)Desviación modelo esférico
maps.plot(1, 3, T)*Una vez más, se encuentra que el mejor modelo es el gaussiano, pues los modelos esférico y exponencial, cuentan con menos variación únicamente en los puntos muestreados.
Predicción
summary(geodatoslatlong)## Number of data points: 111
##
## Coordinates summary
## long lat
## min 113.67 -43.49
## max 153.47 -10.58
##
## Distance summary
## min max
## 0.222036 39.948813
##
## Data summary
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 9.815563 20.176630 23.356290 23.928424 27.313460 34.336910
variogramalatlong=variog(geodatoslatlong,option = "bin")## variog: computing omnidirectional variogram
gauss_fit_fix_latlong <- variofit(variogramalatlong, cov.model = "gaussian", fix.nugget = F)## 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 "36.29" "12.29" "4.84" "0.5"
## status "est" "est" "est" "fix"
## loss value: 130720.717504019
min(geodatoslatlong$coords[,1]) #x## [1] 113.67
max(geodatoslatlong$coords[,1])## [1] 153.47
min(geodatoslatlong$coords[,2])## [1] -43.49
max(geodatoslatlong$coords[,2])## [1] -10.58
geodatos_grid=expand.grid(lat=seq(113.67,153.47,l=100),long=seq(-43.49,-10.58,l=100))
plot(geodatos_grid)
points(temper[,c(3,2)],col="red",pch=16)krig_temp_latlong <- krige.conv(geodatoslatlong, loc=geodatos_grid,
krige=krige.control(obj.model=gauss_fit_fix_latlong))## krige.conv: model with constant mean
## krige.conv: Kriging performed using global neighbourhood
par(mfrow=c(1,1))
image(krig_temp_latlong, main="kriging Predict", xlab="Lat", ylab="Long")contour(krig_temp_latlong,main="kriging Predict", add=TRUE, drawlabels=TRUE,filled=TRUE)Desviación
image(krig_temp_latlong, main="kriging StDv Predicted",val=sqrt(krig_temp_latlong$krige.var), xlab="East", ylab="North")contour(krig_temp_latlong,main="kriging StDv Predict",val=sqrt(krig_temp_latlong$krige.var), add=TRUE, drawlabels=TRUE,filled=TRUE)Mapa final Kriging temperatura de Australia
mat_imagen=data.frame(geodatos_grid,krig_temp_latlong$predict)
temp_m1_raster=rasterFromXYZ(mat_imagen)
temp_m1_raster_austr=mask(temp_m1_raster,austr)
plot(temp_m1_raster_austr)
plot(austr,add=TRUE)crs(temp_m1_raster_austr)=crs(austr)
crs(temp_m1_raster_austr)=CRS("+init=epsg:4326")
pal <- colorNumeric(c("blue", "green", "yellow", "orange", "red"), values(temp_m1_raster_austr),
na.color = "transparent")
leaflet() %>% addProviderTiles(providers$Esri.NatGeoWorldMap) %>% addRasterImage(temp_m1_raster_austr,colors = pal)