15  Special cases in geostatistics


Download slides PDF

The PDF contains what was shown during the lecture. Some of these websites include additional text in light gray.

Geostatistical model: 2 special cases

 

There are many special cases for which the geostatitsical model has been expanded. Let’s have a look at two of them:

  • 2 special cases to expand the geostatistical model
    • lognormal kriging
    • anisotropy

pro memoria: Model for Gaussian spatial data


Model for data: \(Y_{i} = S(\mathbf{x}_{i}) + Z_{i} = \mu(\mathbf{x}_{i}) + E(\mathbf{x}_{i}) + Z_{i}\)


  • with \(Y_{i}\): \(i^{\text{th}}\) datum; \(S(\mathbf{x}_{i})\): “signal” (true quantity) at location \(\mathbf{x}_{i}\); \(\mu(\mathbf{x}_{i})\): trend

  • \(\{E(\mathbf{x}_{i})\}\): a zero-mean Gaussian process, parametrized by covariance function \(\gamma(\mathbf{h}; \mathbf{\theta})\) or variogram \(V(\mathbf{h}; \mathbf{\theta})\)

  • \(Z_{i}\): iid Gaussian measurement error with variance \(\tau^2\)

Trend \(\mu(\mathbf{x}_{i})\) modeled by linear regression model with spatial covariates \(d_{k}(\mathbf{x}_{i})\)

\[ \mu(\mathbf{x}_{i}) = \sum_{k} d_{k}(\mathbf{x}_{i}) \beta_{k} = \mathbf{d}(\mathbf{x}_{i})^{T} \mathbf{\beta} \]

15.1 Lognormal universal kriging

Gaussian model fitted to log-transformed response variable \(Y(\mathbf{x}) = \log\big(U(\mathbf{x})\big)\)

(e.g. often pollution datasets)


⇒ Computing UK predictions for log-transformed response

⇒ How should we back-transform to original scale of response?


Lognormal distribution \[ Y = \log(U) \sim {\cal N}(\mu_{Y},\sigma_{Y}^2) \]

Expectation and variance of \(U\) \[ \begin{eqnarray*} \mathbb{E}[U] & = & \mu_{U} = \exp(\mu_{Y} + 0.5 \, \sigma_{Y}^2)\\ Var[U] & = & \mu_{U}^2 (\exp(\sigma_{Y}^2) -1 ) \end{eqnarray*} \]

Backtransformation for lognormal universal kriging

 

\(\exp\big(\hat{S}_{\mathrm{k}}(\mathbf{x}^\prime)\big)\) is a biased predictor of \(U(\mathbf{x}^\prime)\)

Unbiased back-transformation \[ \hat{U}_{\mathrm{lk}}(\mathbf{x}^\prime) = \exp \left(\hat{S}_{\mathrm{k}}(\mathbf{x}^\prime)+0.5\left\{Var[S(\mathbf{x}^\prime)] - Var[\hat{S}_{\mathrm{k}}(\mathbf{x}^\prime)]\right\}\right) \]

Limits of prediction intervals can be back-transformed directly by \(\exp()\).

Back-transformation implemented in function lgnpp of R package georob.

Example: Lognormal UK Meuse zinc data

library(georob)
library(mapview)
data(meuse)
coordinates(meuse) <- ~x+y
proj4string(meuse) <- CRS("+init=epsg:28992")
mapview(meuse, zcol = "zinc", map.types = "Esri.WorldImagery")

Example Meuse zn: Response distribution

par(mfrow=c(1,2))
hist(meuse@data$zinc, breaks = 20)
hist(log(meuse@data$zinc), breaks = 20)

Example Meuse zn: OLS residuals

par(mfrow = c(1,2))
plot(lm(zinc ~ dist, meuse), 2)
plot(lm(log(zinc) ~ dist, meuse), 2)

Example Meuse zn: REML fit

r.logzn <- georob(log(zinc)~sqrt(dist), meuse, locations=~x+y, 
                  variogram.model="RMexp", 
                  param=c(variance=0.15, nugget=0.05, scale=200),
                  tuning.psi=1000, control=control.georob(
                    cov.bhat=TRUE, cov.bhat.betahat=TRUE))
r.logzn

Tuning constant:  1000 

Fixed effects coefficients:
(Intercept)   sqrt(dist)  
      6.985       -2.567  

Variogram:  RMexp 
        variance    snugget(fixed)            nugget             scale  
         0.14910           0.00000           0.04867         192.52854  

Example Meuse zn: REML variogram

plot(r.logzn, lag.dist.def=60, max.lag=1500)

Example Meuse zn: Universal kriging prediction

data(meuse.grid)
coordinates(meuse.grid) <- ~x+y
gridded(meuse.grid) <- TRUE
r.luk <- predict(r.logzn, newdata=meuse.grid, 
  control=control.predict.georob(extended.output=TRUE))
str(r.luk@data)
'data.frame':   3103 obs. of  8 variables:
 $ pred           : num  7.03 7.05 6.75 6.49 7.07 ...
 $ se             : num  0.362 0.335 0.342 0.349 0.288 ...
 $ lower          : num  6.32 6.39 6.08 5.8 6.5 ...
 $ upper          : num  7.73 7.7 7.42 7.17 7.63 ...
 $ trend          : num  6.99 6.99 6.7 6.45 6.99 ...
 $ var.pred       : num  0.0388 0.0539 0.0437 0.0357 0.0787 ...
 $ cov.pred.target: num  0.0285 0.0453 0.0379 0.0315 0.0724 ...
 $ var.target     : num  0.149 0.149 0.149 0.149 0.149 ...
 - attr(*, "variogram.object")=List of 1
  ..$ :List of 9
  .. ..$ variogram.model: chr "RMexp"
  .. ..$ param          : Named num [1:4] 0.1491 0 0.0487 192.5285
  .. .. ..- attr(*, "names")= chr [1:4] "variance" "snugget" "nugget" "scale"
  .. ..$ fit.param      : Named logi [1:4] TRUE FALSE TRUE TRUE
  .. .. ..- attr(*, "names")= chr [1:4] "variance" "snugget" "nugget" "scale"
  .. ..$ isotropic      : logi TRUE
  .. ..$ aniso          : Named num [1:5] 1 1 90 90 0
  .. .. ..- attr(*, "names")= chr [1:5] "f1" "f2" "omega" "phi" ...
  .. ..$ fit.aniso      : Named logi [1:5] FALSE FALSE FALSE FALSE FALSE
  .. .. ..- attr(*, "names")= chr [1:5] "f1" "f2" "omega" "phi" ...
  .. ..$ sincos         :List of 6
  .. .. ..$ co: num 6.12e-17
  .. .. ..$ so: num 1
  .. .. ..$ cp: num 6.12e-17
  .. .. ..$ sp: num 1
  .. .. ..$ cz: num 1
  .. .. ..$ sz: num 0
  .. ..$ rotmat         : num [1:2, 1:2] 1.00 -6.12e-17 6.12e-17 1.00
  .. ..$ sclmat         : Named num [1:2] 1 1
  .. .. ..- attr(*, "names")= chr [1:2] "" "f1"
 - attr(*, "psi.func")= chr "logistic"
 - attr(*, "tuning.psi")= num 1000
 - attr(*, "type")= chr "signal"

Example Meuse zn: Unbiased backtransformation

r.luk <- lgnpp(r.luk)
str(r.luk@data)
'data.frame':   3103 obs. of  12 variables:
 $ pred           : num  7.03 7.05 6.75 6.49 7.07 ...
 $ se             : num  0.362 0.335 0.342 0.349 0.288 ...
 $ lower          : num  6.32 6.39 6.08 5.8 6.5 ...
 $ upper          : num  7.73 7.7 7.42 7.17 7.63 ...
 $ trend          : num  6.99 6.99 6.7 6.45 6.99 ...
 $ var.pred       : num  0.0388 0.0539 0.0437 0.0357 0.0787 ...
 $ cov.pred.target: num  0.0285 0.0453 0.0379 0.0315 0.0724 ...
 $ var.target     : num  0.149 0.149 0.149 0.149 0.149 ...
 $ lgn.pred       : num  1189 1204 902 694 1215 ...
 $ lgn.se         : num  440 409 314 249 354 ...
 $ lgn.lower      : num  554 595 438 331 667 ...
 $ lgn.upper      : num  2286 2215 1673 1299 2064 ...
 - attr(*, "variogram.object")=List of 1
  ..$ :List of 9
  .. ..$ variogram.model: chr "RMexp"
  .. ..$ param          : Named num [1:4] 0.1491 0 0.0487 192.5285
  .. .. ..- attr(*, "names")= chr [1:4] "variance" "snugget" "nugget" "scale"
  .. ..$ fit.param      : Named logi [1:4] TRUE FALSE TRUE TRUE
  .. .. ..- attr(*, "names")= chr [1:4] "variance" "snugget" "nugget" "scale"
  .. ..$ isotropic      : logi TRUE
  .. ..$ aniso          : Named num [1:5] 1 1 90 90 0
  .. .. ..- attr(*, "names")= chr [1:5] "f1" "f2" "omega" "phi" ...
  .. ..$ fit.aniso      : Named logi [1:5] FALSE FALSE FALSE FALSE FALSE
  .. .. ..- attr(*, "names")= chr [1:5] "f1" "f2" "omega" "phi" ...
  .. ..$ sincos         :List of 6
  .. .. ..$ co: num 6.12e-17
  .. .. ..$ so: num 1
  .. .. ..$ cp: num 6.12e-17
  .. .. ..$ sp: num 1
  .. .. ..$ cz: num 1
  .. .. ..$ sz: num 0
  .. ..$ rotmat         : num [1:2, 1:2] 1.00 -6.12e-17 6.12e-17 1.00
  .. ..$ sclmat         : Named num [1:2] 1 1
  .. .. ..- attr(*, "names")= chr [1:2] "" "f1"
 - attr(*, "type")= chr "signal"

Example Meuse zn: Predicted maps

library(terra)
r.luk <- rast(r.luk)
par(mfrow=c(1,2))
plot(r.luk["^pred$"], main = "UK prediction log(zn)")
plot(r.luk["lgn.pred"], main = "LUK prediction zn")

Example Meuse zn: Predicted standard errors

par(mfrow=c(1,2))
plot(r.luk["^se$"], main = "UK standard error log(zn)")
plot(r.luk["lgn.se"], main = "LUK stanard error zn")

15.2 Anisotropic variograms

Spatial auto-correlation can vary from one direction to the other, i.e. it can be anisotropic.

In many instances the anisotropy is such that it could be made isotropic by a simple linear transformation of the spatial coordinates. ⇒ geometrically anisotropic variogram function

Idea: rotate and stretch/shrink components of \(\mathbf{x}\) such that the stochastic process is isotropic in the transformed coordinate system

\[ V(h^*) = V\left( \sqrt{(\mathbf{h}\mathbf{A})^\mathrm{T}\mathbf{A}\mathbf{h}} \right) \]

Iso-semivariances contours are ellipsoids in space of non-transformed coordinates and are mapped by transformation:

\[ \mathbf{A} = \left[\begin{array}{cc} 1/\alpha & 0\\ 0 & 1/(f_{1}\alpha) \end{array}\right] \left[\begin{array}{cc} \cos(\omega) & \sin(\omega) \\ -\sin(\omega) & \cos(\omega) \end{array}\right] \]

Example: elevation data

data(elevation, package="georob")
d.elevation <- elevation
d.elevation$res <- residuals(lm(height~y, d.elevation))
plot(y~x, d.elevation, cex=sqrt(abs(res)), asp=1,
  col=c("blue", NA, "orange")[sign(res)+2])

Example: elevation data - directional sample variogram

r.sv <- sample.variogram(d.elevation$res, 
  locations=as.matrix(d.elevation[, c("x","y")]),
  lag.dist.def=0.5, xy.angle.def=c(0, 45, 135, 180))
summary(r.sv)

Sample variogram estimator: qn 

Summary of lag distances
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.3812  2.2244  4.2278  4.1295  6.1756  8.2759 

Summary of number of pairs per lag and distance classes
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   1.00   11.00   45.00   40.18   63.00   73.00 

Angle classes in xy-plane: (-45,45] (45,135] 
Angle classes in xz-plane: [0,180] 

Example: elevation data - directional sample variogram

plot(r.sv)

Example: elevation data - fitted directional variogram

r.exp <- fit.variogram.model(r.sv, 
  variogram.model="RMexp", 
  param=c(variance=1500, nugget=10, scale=4),
  aniso = default.aniso(f1 = 0.4, omega = 0),
  fit.aniso = default.fit.aniso(f1 = TRUE, omega = TRUE))
r.exp

Variogram:  RMexp 
        variance    snugget(fixed)            nugget             scale  
       1.820e+03         0.000e+00         1.289e-07         1.256e+02  

              f1         f2(fixed)             omega        phi(fixed)  
        0.006757          1.000000         17.415945         90.000000  
     zeta(fixed)  
        0.000000  

Example: elevation data - fitted directional variogram

plot(r.sv)
lines(r.exp, xy.angle=c(0, 90))