- Estadística espacio temporal
- Modelo general
- Función de covarianza espacio temporal
- Covarianza basada en predicción espatio Temporal
- Ejemplos de aplicación (ozono en vias trenes y velocidad del viento)
Se dice que un proceso aleatorio \( Z(·; ·) \) tiene función de covarianza espacio-temporal separable si, para todo \( s_1,t_1 \in \mathbb{R}^d \) y \( s_2,t_2 \in \mathbb{R} \) \[ Cov(Z(s_1; t_1), Z(s_2; t_2)) = C^{(s)}(s_1, s_2) \cdot C^{(t)}(t_1, t_1) \]
donde \( C^{(s)} \) y \( C^{(t)} \) son covarianzas espaciales y temporales funciones, respectivamente.
Una consecuencia obvia de la condición de separabilidad (aunque poco realista) de funciones de covarianza espacio-temporales es dada por producto de la covarianza espacial y temporal individual funciones.
Podemos probar que el estimador de \( \lambda_0 \) es \( \hat{\lambda}_0C(s_0;t_0)C_Z^{-1} \) y por lo tanto, tenemos el simple espacio-temporal predictor de kriging: \[ \hat{Z}_Y =C(s_0;t_0)'C^{-1}_zZ \] donde \( C_Z =Cov(Z) \) y \( C(s_0; t_0)'= Cov(Z_Y(s_0; t_0), Z) \). El espacio-temporal asociado El error estándar de kriging simple (s.e.) es: \[ \sigma^2_{k}(s_0;t_0)=[Var(Z_Y(s_0,;t_0))-C(s_0;t_0)'C^{-1}_ZC(s_0,t_0)] \]
Definimos el semivariograma espacio temporal empírico \( \hat{\gamma}(h_k,\tau_p) \), como promedio de incrementos al cuadrado para una clase \( (h_k,\tau_p) \), \[ \hat{\gamma}(h_k,\tau_p)=\frac{1}{2N(h_k,\tau_p)}\sum_{(s,t)\in N(h_K,\tau_p)}[Z(s_i,t_i)-Z(s_j,t_j)]^2 \]
Paquetes de para datos espacio-temporales
gstat puede realizar kriging espacio-temporal explotando las funcionalidades del librería spacetime, que fue desarrollado por el mismo equipo que gstat. spacetime tenemos dos formas de representar datos espacio-temporales: formatos STFDF y STIDF. En este caso tenemos datos recopilados sobre tranvías que se mueven por la ciudad de Zurich. Esto significa que la ubicación de los sensores no es uniforme en toda la ventana de muestreo.
La creación de objetos STIDF es bastante simple, solo tenemos que desensamblar el marco de datos que tenemos en un componente espacial, temporal y variables del problema, y luego fusionarlos para crear el objeto STIDF.
#librerias
library(gstat)
library(sp)
library(spacetime)
library(raster)
library(rgdal)
library(rgeos)
library(readr)
ozono.csvozono <- read_csv("~/Desktop/curso_glm_utb/geo-estadistica/pres.geo/sec_6_geo/ozono.csv")
#SpatialPointsDataFrame
coordinates(ozono)=~LON+LAT
projection(ozono)=CRS("+init=epsg:4326")
#Transformacion en proyeccion Mercator
ozone.UTM <- spTransform(ozono,CRS("+init=epsg:3395"))
Ahora tenemos el objeto ozone.UTM, que es un SpatialPointsDataFrame con coordenadas en metros.
SpatialPoints, con las ubicaciones de los sensores en un momento dado:ozoneSP <- SpatialPoints(ozone.UTM@coords,CRS("+init=epsg:3395"))
SpatialPoints en la librería sp. data.frame con las coordenadas de cada punto. zerodist:dupl <- zerodist(ozoneSP)
ozoneDF <- data.frame(PPB=ozone.UTM$ozone_ppb[-dupl[,2]])
Como puede ver, se eliminan los puntos duplicados al excluir las filas del objeto ozone.UTM con los índices incluidos en una de las columnas del objeto dupl.
Podemos usar el mismo procedimiento para la parte temporal
ozoneTM <- as.POSIXct(ozone.UTM$TIME[-dupl[,2]],tz="CET")
Combinación de los objetos: ozoneSP, ozoneDF y ozoneTM de clase STIDF:
timeDF <- STIDF(ozoneSP,ozoneTM,data=ozoneDF)
stplot(timeDF)
variogramST.Parámetros
tunit="hours": debemos especificar las unidades de tiempo (tunits) o los retardos de tiempo (tlags). assumeRegular=FALSE: si la serie de tiempo debe asumirse como regular. Se supone que el primer paso del tiempo es representativo de toda la serie. Tenga en cuenta que los retardos temporales se consideran por índice, y no se verifica si los pares realmente tienen la distancia de separación deseada.var <- variogramST(PPB~1,data=timeDF,tunit="hours",assumeRegular=FALSE,na.omit=TRUE)
Atención!!! Esta parte toma bastante tiempo(10 horas aprox.), por lo tanto tenga paciencia.
plot(var,map=TRUE)
O también, podemos visualizarlo en tres dimensiones con el parámetro wireframe
plot(var,wireframe=TRUE)
A continuación, vemos el código para algunos posibles modelos.
Los modelos de variograma, en gstat tienen 5 opciones: separable(separable), suma de producto(productSum), métrica(metric), suma métrica(sumMetric) y suma simple(simpleSumMetric).
Puede encontrar más información para adaptarse a este modelo, incluidas todas las ecuaciones que se presentan a continuación, en (Gräler et al., 2015).
# límites inferior
lim_inf <- c(sill.s = 0, range.s = 10, nugget.s = 0,sill.t = 0, range.t = 1, nugget.t = 0,sill.st = 0, range.st = 10, nugget.st = 0, anis = 0)
#límites superior
lim_sup<- c(sill.s = 200, range.s = 1000, nugget.s = 100,sill.t = 200, range.t = 60, nugget.t = 100,sill.st = 200, range.st = 1000, nugget.st = 100,anis = 700)
Para crear un modelo de variograma separable, debemos proporcionar un modelo para el componente espacial, uno para el componente temporal, más el umbral general:
separable <- vgmST("separable", space = vgm(-60,"Sph", 500, 1),time = vgm(35,"Sph", 500, 1), sill=0.56)
grafiquemos el variograma del modelo separable
plot(var,separable,map=FALSE)
# ajuste del modelo de variograma separable
# con los parametros ajustados por defecto (fit.method=0)
separable_Vgm <- fit.StVariogram(var, separable, fit.method=0)
# error cuadratico medio del modelo de variograma separable
attr(separable_Vgm,"MSE")
# ajuste del modelo de variograma separable
# con los parametros ajustados por lim_inf, lim_sup
separable_Vgm <- fit.StVariogram(var, separable, fit.method=11,method="L-BFGS-B", stAni=5, lower=lim_inf,upper=lim_sup)
# error cuadratico medio del modelo de variograma separable
# con los parametros ajustados por lim_inf, lim_sup
attr(separable_Vgm, "MSE")
Veamos el gráfico del variograma
plot(var,separable_Vgm,map=F)
extractParextractPar(separable_Vgm)
range.s nugget.s range.t nugget.t sill
Existen diferentes tipos de modelos separables. Presentamos el siguiente ejemplo:
\[ C(h,u) = \frac{\sigma^2}{(|h|^{2\lambda}+1)^\tau} \exp\Big\{ - \frac{c\|u\|^{2\lambda}}{(|h|^{2\lambda}+1)^{\beta\lambda}} \Big\} \]
donde \( \tau \) determina la suavidad de la correlación temporal, mientras que \( \lambda \) determina la suavidad de la correlación espacial, \( c \) determina la fuerza de la correlación espacial, y \( \beta \in (0,1) \) determina la fuerza de la interacción espacio/tiempo.
\[ C_{prod}(h, u) = k\cdot C^{(s)}(h) \cdot C^{(t)}(u)+ C^{(s)}(h)+ C^{(t)}(u) \]
para \( k> 0 \).
vgmST necesitamos proporcionar el componente espacial y temporal, más el valor del parámetro \( k \) (que debe ser positivo):prodSumModel <- vgmST("productSum",space = vgm(1, "Exp", 150, 0.5),time = vgm(1, "Exp", 5, 0.5),k = 50)
A continuación, podemos continuar con el proceso de adaptación y podemos verificar el MSE con las siguientes dos líneas:
# ajuste del modelo de variograma prodSumModel
# con los parametros ajustados por lim_inf
prodSumModel_Vgm <- fit.StVariogram(var, prodSumModel,method = "L-BFGS-B",lower=lim_inf)
# error cuadratico medio del modelo de variograma productSum
attr(prodSumModel_Vgm, "MSE")
\[ C_{m}(h, u) = C_{conjunta}\sqrt{h^2+ (k\cdot u)^2} \]
R, el parámetro de anisotropia k, se llama stAni y la creación de un modelo de métrica en vgmST se puede hacer de la siguiente manerametric <- vgmST("metric", joint = vgm(50,"Mat", 500, 0), stAni=200)
El ajuste automático produce el siguiente MSE
# ajuste por defecto del modelo de variograma métrico
metric_Vgm <- fit.StVariogram(var, metric, method="L-BFGS-B",lower=lim_inf)
# error cuadratico medio del modelo de variograma métrico
attr(metric_Vgm, "MSE")
Podemos ver el gráfico de este modelo para verificar visualmente su precisión
plot(var,metric_Vgm,map=FALSE)
\[ C_{sm}(h, u) = C^{(s)}(h) + C^{(t)}(u) + C^{(t)}(u) + C_{conjunta}\sqrt{h^2+ (k\cdot u)^2} \]
R esto se logra con la siguiente línea de códigosumMetric <- vgmST("sumMetric", space = vgm(psill=5,"Sph", range=500, nugget=0),time = vgm(psill=500,"Sph", range=500, nugget=0), joint = vgm(psill=1,"Sph", range=500, nugget=10), stAni=500)
El ajuste del modelo suma métrica es
sumMetric_Vgm <- fit.StVariogram(var, sumMetric, method="L-BFGS-B",lower=lim_inf,upper=lim_sup,tunit="hours")
attr(sumMetric_Vgm, "MSE")
Grafiquemos el variograma suma métrica
plot(var,sumMetric_Vgm,map=FALSE)
nugget. nugget en cada componente, ya que necesitamos establecer un efecto de nugget para los tres.SimplesumMetric <- vgmST("simpleSumMetric",space = vgm(5,"Sph", 500, 0),time = vgm(500,"Sph", 500, 0), joint = vgm(1,"Sph", 500, 0), nugget=1, stAni=500)
Esto devuelve un modelo similar al modelo suma métrica
Veamos el error cuadrático medio
SimplesumMetric_Vgm <- fit.StVariogram(var, SimplesumMetric,method = "L-BFGS-B",lower=pars.l)
attr(SimplesumMetric_Vgm, "MSE")
Grafiquemos el variograma suma métrica
plot(var,sumMetric_Vgm,map=FALSE)
plot(var,list(separable_Vgm, prodSumModel_Vgm, metric_Vgm, sumMetric_Vgm, SimplesumMetric_Vgm),all=T,wireframe=T)
carreteras_zu.shp de la red de carreteras para el área alrededor de Zurich, luego la recorté para que coincidiera con la extensión de mi área de estudio, y luego creé la grilla espacial.carreteras <- shapefile("~/Desktop/curso_glm_utb/geo-estadistica/pres.geo/sec_6_geo/datos_shp_vias_zu/vias_zu.shp")
Luego cambiemos la proyección de este objeto de a UTM, de modo que sea comparable con lo que usé hasta ahora.
carr.UTM <- spTransform(carreteras,CRS("+init=epsg:3395"))
Esto nos muestra la red de carreteras alrededor de las ubicaciones donde se recopilaron los datos.
Veamos el resultado con las siguientes lineas de código
plot(carr.UTM, cex=.2, pch=1)
plot(ozone.UTM,col="blue",add=T,cex=.5, pch=1)
donde las carreteras carr.UTM están en negro y los puntos de datos están representados en rojo. Con esta selección ahora puedo usar la función spsample para crear una cuadrícula aleatoria de puntos a lo largo de las líneas de la carretera. Esto genera la siguiente grilla.
sp.grid.UTM <- spsample(carr.UTM,n=1500,type="random")
seqtm.grid <- seq(as.POSIXct('2011-12-12 06:00 CET'),as.POSIXct('2011-12-14 09:00 CET'),length.out=5)
POSIXct entre las dos fechas/tiempos proporcionados. STF para fusionar datos espaciales y temporales en una cuadrícula espacio-temporal, asígrid.ST <- STF(sp.grid.UTM,tm.grid)
Esto se puede usar como datos nuevos en la función kriging.
Kriging
krigeST y el variograma que mejor nos resultó(sumMetric_Vgm) para realizar la interpolaciónpred_krig <- krigeST(PPB~1, data=timeDF, modelList=sumMetric_Vgm, newdata=grid.ST)
Podemos graficar los resultados nuevamente usando la función stplot
stplot(pred_krig)
Este ejemplo pertenece a la librería: 𝚐𝚜𝚝𝚊𝚝, 𝚜𝚙𝚊𝚌𝚎𝚝𝚒𝚖𝚎. El documento original es de Haslett y Raftery (1989). La discusión sobre el uso de los datos con R en Pebesma (2012). Ver también Graler et al. (2016).
Datos velocidades de viento en Irlanda
library(gstat)
data("wind")
head(wind) #velocidades y tiempo
head(wind.loc) #ubucaciones
SpatialPointsDataFrame que por ejemplo, se puede trazarlibrary(sp)
wind.loc$y = as.numeric(char2dms(as.character(wind.loc[["Latitude"]])))
wind.loc$x = as.numeric(char2dms(as.character(wind.loc[["Longitude"]])))
coordinates(wind.loc) = ~x+y
proj4string(wind.loc) = "+proj=longlat +datum=WGS84"
head(wind.loc)
Veamos el mapa con las ubicaciones de cada lugar en el mapa
# Visualizar las ubicaciones de las estaciones en el mapa de Irlanda
library(mapdata)
map("worldHires", xlim = c(-11,-5.4), ylim = c(51,55.5))
plot(wind.loc, add=TRUE, pch=16)
text(coordinates(wind.loc), pos=1, label=wind.loc$Station)
Recodifiquemos las columnas de tiempo a una estructura de datos de tiempo apropiada
wind$time = ISOdate(wind$year+1900, wind$month, wind$day)
wind$jday = as.numeric(format(wind$time, '%j'))
head(wind[-c(4:15)])
Veamos el gráfico de los datos de la serie temporal de velocidad del viento para Dublín
plot(DUB~time, wind, type= 'l', ylab = "windspeed (knots)", main = "Dublin")
Veamos la tendencia de los datos de viento
windsqrt = sqrt(0.5148 * as.matrix(wind[4:15]))
Jday = 1:366
windsqrt = windsqrt - mean(windsqrt)
dia_promedio = sapply(split(windsqrt, wind$jday), mean)
plot(dia_promedio ~ Jday)
lines(lowess(dia_promedio ~ Jday, f = 0.1))
Calculemos la velocidad promedio del viendo
viento_prom = lowess(dia_promedio ~ Jday, f = 0.1)$y[wind$jday]
velocity = apply(windsqrt, 2, function(x) { x - viento_prom})
Veamos la dependencia espacial (correlación)
pts = coordinates(wind.loc[match(names(wind[4:15]), wind.loc$Code),])
dists = spDists(pts, longlat=TRUE)
corv = cor(velocity)
sel = !(as.vector(dists) == 0)
plot(as.vector(corv[sel]) ~ as.vector(dists[sel]), xlim = c(0,500), ylim = c(.4, 1), xlab = "distance (km)", ylab = "correlation")
Dependencia temporal de los datos de viento
acf(velocity[,7])
tdiscr = 0:40
lines(tdiscr, exp(- tdiscr/1.5))
R de la clase correspondiente(librería sp), para luego, ser manipulado de manera más conveniente, es decir, en visualización y análisis.Creemos un SpatialPoints con los datos de viento y agreguemosle una proyección adecuada
wind.loc = wind.loc[match(names(wind[4:15]), wind.loc$Code),]
pts = coordinates(wind.loc[match(names(wind[4:15]), wind.loc$Code),])
rownames(pts) = wind.loc$Station
pts = SpatialPoints(pts, CRS("+proj=longlat +datum=WGS84"))
library(spacetime)
library(rgdal)
utm29 = CRS("+proj=utm +zone=29 +datum=WGS84")
pts = spTransform(pts, utm29)
wind.data = stConstruct(velocity, space = list(values = 1:ncol(velocity)), time = wind$time, SpatialObj = pts, interval = TRUE)
class(wind.data)
Veamos la tendencia de las series de los datos de viento a travez del tiempo para cada ubicación
scales=list(x=list(rot = 45))
stplot(wind.data[1:12,"1974-11-01::1974-11-30"], mode = "tp", scales = scales, xlab = NULL)
wind.data, veamos el modelo exponencial separable con los siguientes parámetros, motivados por la consideración de dependencia anteriorlibrary(gstat)
v = vgmST("separable", space = vgm(1, "Exp", 750*1000), time = vgm(1, "Exp", 1.5 * 3600 * 24),sill=0.3)
library(maptools)
m = map2SpatialLines(
map("worldHires", xlim = c(-11.5,-6.0), ylim = c(51.3,55.0), plot=F))
proj4string(m) = "+proj=longlat +datum=WGS84"
m = spTransform(m, utm29)
Creamos una grilla en el espacio para la predicción para el espacio y escogemos algún mes del año para hacer la estimación
grd = SpatialPixels(SpatialPoints(makegrid(m, n = 300)),proj4string = proj4string(m))
#mes arbitrario
wind.data2 = wind.data[, "1961-04"]
#wind.data2 = wind.data[, "1961-04::1964-04"] #puede hacerlo por dias o años
Creamos una grilla(vector) en el espacio para la predicción para el tiempo
#grilla(vector) para el tiempo
n = 10
library(xts)
tgrd <- xts(1:n, seq(min(index(wind.data2)), max(index(wind.data2)),length = n))
#juntamos las grillas de prediccion en el tiempo y el espacio
pred.grd <- STF(grd, tgrd)
#estimacion Kriging
pred <- krigeST(values ~ 1, wind.data2, pred.grd,modelList=v, computeVar = TRUE)
#resultados del modelo kriging en un formato adecuado
wind.ST <- STFDF(grd, tgrd, as.data.frame(pred$var1.pred))
wind.STvar <- STFDF(grd, tgrd, as.data.frame(pred$var1.var))
colnames(wind.ST@data) <- "sqrt_speed"
colnames(wind.STvar@data) <- "sqrt_speed"
Veamos el gráfico de las estimaciones del modelo espacio temporal
library(RColorBrewer)
#agreguemos el mapa con layout en un tono de gris suave y los puntos con signos "+" de color azul
layout <- list(list("sp.lines", m, col = "gray"),list("sp.points", pts, first = FALSE, cex = 0.5, col = "blue"))
# grafico con stplot
stplot(wind.ST, col.regions = brewer.pal(11, "RdBu")[-c(10, 11)],at = seq(-1.375, 1, by = 0.25),par.strip.text = list(cex = 0.7), sp.layout = layout,animate=0)
Veamos también el gráfico de la varianza
stplot(wind.STvar, col.regions = brewer.pal(11, "RdBu")[-c(10, 11)],at = seq(0, .15, by = 0.025),par.strip.text = list(cex = 0.7), sp.layout = layout,animate=0)