11 ottobre 2013
1 Modello di base
Il modello concettuale di base della geostatistica è:
• Se lo scopo primario è la previsione si darà più peso alla componete di piccola sca-
la scegliendo una struttura parsimoniosa per µ(s) insieme ad una qualche forma di
stazionarietà
µ(s) = 0 + 1X + 2Y (2)
2 2
µ(s) = 0 + 1X + 2Y + 3 XY + 4X + 5Y (3)
3 3 2 2
µ(s) = 0 + 1X + 2Y + 3X Y + 4 XY + 5 XY + 6X + 7Y (4)
Al crescere del grado del polinomio otteniamo superfici sempre più “rigide e modelli che
coinvolgono un numero sempre più elevato di parametri. Vediamo come stimare in R que-
sto tipo di superfici.
Inizializziamo le librerie che ci interessano costruiamo la superficie dei dati originali per rap-
presentarla con persp, poi costruiamo in aq.fit.1 i valori del trend lineare come regressione
dei valori osservati sulle coordinate ed infine estraiamo i residui.
1
> rm(list = ls())
> source("myfunction.R")
> library(spatstat)
> library(spdep)
> library(scatterplot3d)
> library(sgeostat)
> library(geoR)
> library(akima)
> data(wolfcamp)
> data(nc.sids)
> data(longleaf)
> wolf.interp <- interp(wolfcamp$coords[, 1], wolfcamp$coords[, 2], wolfcamp$data)
> x <- wolfcamp$coords[, 1]
> y <- wolfcamp$coords[, 2]
> z <- wolfcamp$data
> aq.fit.1 <- lm(z ~ x + y)
> xgrid <- seq(min(wolfcamp$coords[, 1]), max(wolfcamp$coords[, 1]), length = 20)
> ygrid <- seq(min(wolfcamp$coords[, 2]), max(wolfcamp$coords[, 2]), length = 20)
> aq.grid <- expand.grid(x = xgrid, y = ygrid)
> aq.surf <- predict(aq.fit.1, newdata = aq.grid)
> res.interp <- interp(wolfcamp$coords[, 1], wolfcamp$coords[, 2], aq.fit.1$res)
2
> par(mfrow = c(1, 3))
> persp(wolf.interp$x, wolf.interp$y, wolf.interp$z, xlab = "x", ylab = "y", zlab = NULL,
+ theta = 60, phi = 30, expand = 0.9, col = "green", ltheta = 120, shade = 0.75,
+ ticktype = "simple", main = "Perspective plot", box = TRUE)
> persp(xgrid, ygrid, matrix(aq.surf, 20, 20), xlab = "x", ylab = "y", zlab = "trend",
+ theta = 60, phi = 30, expand = 0.9, col = "green", ltheta = 120, shade = 0.75,
+ ticktype = "simple", main = "Trend lineare", box = TRUE)
> persp(res.interp$x, res.interp$y, res.interp$z, xlab = "x", ylab = "y", zlab = "residuals"
+ theta = 60, phi = 30, expand = 0.9, col = "green", ltheta = 120, shade = 0.75,
+ ticktype = "simple", main = "Residui", box = TRUE)
residu
trend
terp$z
als
x
y y y
Costruiamo con lo stesso schema un trend del secondo ordine ovvero parabolico come
nella (3)
3
> res.interp <- interp(wolfcamp$coords[, 1], wolfcamp$coords[, 2], aq.fit.2$res)
residu
trend
terp$z
als
x
y y y
4
> aq.fit.3 <- lm(z ~ x + y + I(x^2) + I(y^2) + x * y + I(x^3) + I(y^3) + I(x^2) *
+ y + I(y^2) * x)
> aq.surf <- predict(aq.fit.3, newdata = aq.grid)
> res.interp <- interp(wolfcamp$coords[, 1], wolfcamp$coords[, 2], aq.fit.3$res)
residu
trend
terp$z
als
x
y y y
5
Osservando i grafici vediamo che la struttura dei residui non cambia in modo sostanziale al
variare del trend. Per i dati wolfcamp il trend cubico è chiaramente poco realistico, mentre
un trend lineare o parabolico sembra più plausibile.
La scelta della funzione di trend, come già detto, dipende in larga parte dallo scopo del-
l’analisi, se questo scopo è prevalentemente descrittivo/interpretativo ad esempio nel caso
dei dati wolfcamp, nessuno dei trend polinomiali visti è ottimale. Per ottenere superfici
adeguate a questo scopo vediamo due tecniche non probabilistiche.
Media pesata con l’inverso della distanza La media pesata con l’inverso della di-
stanza è un previsore basato sull’idea che le singole osservazioni non contribuiscono tutte
allo stesso modo nella definizione del valore stimato, ma osservazioni lontane da questo
contribuiscono meno:
n
X
1 p
Ẑ(s0 ) = Pn p
dist(s0 , si ) Z(si ); p 0 (5)
i=1 dist(s0 , si ) i=1
La scelta di p determina il grado di regolarità della superficie che otteniamo. Per sceglierlo
usualmente si utilizza una procedura di cross-validation. In particolare si utilizza il valore
del coefficiente di cross-validation ottenuto come:
Pn
((Ẑ(si ) Z(si ))/ i )2
CV = i=1 (6)
n
dove i è la deviazione standard dei valori osservati meno il valore Z(si ). Sceglieremo il
valore di p che rende minimo questo coefficiente.
Vediamo come nel caso dei dati wolfcamp:
> source("funzionimie.R")
> pp = seq(1, 10, by = 0.5)
> cv = numeric(length(pp))
> for (i in 1:length(pp)) {
+ cv[i] = CV.ID(wolfcamp, pow = pp[i])$CV
+ }
Nel file funzionimie.R è contenuta una funzione che implementa la cross-validation per la
media pesata con l’inverso della distanza. Prima di tutto definiamo un insieme di valori per
p da porre a confronto. Quindi definiamo un vettore che conterrà il valore del coefficiente
di cross-validation per ciascun valore di p, procediamo a implementare in un loop il calcolo
del coefficiente (6) ed infine riportiamo il risultato in un grafico (figura 4).
6
> par(mfrow = c(1, 1))
> plot(pp, cv, xlab = "p", ylab = "CV", pch = 20)
●
0.35
0.30
CV
0.25
●
0.20
●
0.15
●
● ● ● ●
● ● ●
● ●
● ● ●
● ● ●
2 4 6 8 10
Figura 4: Coefficiente di cross-validation per i la media pesata con l’inverso della distanza,
dati wolfcamp
Il valore minimo corrisponde a p = 4 ed è con questo valore che procediamo alla stima
della superficie definendo una griglia di stima 20 ⇥ 20:
7
> persp(xy, xlab = "x", ylab = "y", zlab = NULL, theta = 60, phi = 30, expand = 0.9,
+ col = "green", ltheta = 120, shade = 0.75, ticktype = "simple", main = "",
+ box = TRUE)
Z
Figura 5: Dati wolfcamp superficie stimata con la media pesata con l’inverso della distanza
p=4
Ora costruiamo una rappresentazione approssimata dei residui a partire dalle super-
fici costruite sui dati originali e sulle previsioni con la distanza inversa, si tenga presen-
te che questa procedura ha solo uno scopo illustrativo per poter dare un’idea visuale del
comportamento della parte residuale:
8
> res = wolf.interp$z - xy$z
> persp(xy$x, xy$y, res, xlab = "x", ylab = "y", zlab = NULL, theta = 60, phi = 30,
+ expand = 0.9, col = "green", ltheta = 120, shade = 0.75, ticktype = "simple",
+ main = "", box = TRUE)
res
Figura 6: Dati wolfcamp, stima del trend con la media pesata con l’inverso della distanza
p = 4, rappresentazione dei residui
Thin plate spline Le thin plate spline sono una generalizzazione delle splines unidimen-
sionali. Nelle tecniche basate su splines unidimensionali si utilizzano funzioni polinomiali a
tratti calcolate in un numero ridotto di punti dello spazio detti nodi al fine di stimare funzio-
ni “regolari”. Nel caso di funzioni definite sullo spazio geografico, anziché utilizzare funzioni
polinomiali a tratti, si utilizzano basi bidimensionali, in particolare le radial basis. In gene-
rale data una funzione Z(s) s 2 S indichiamo l’insieme dei nodi con {wi , i = 1, 2, . . . , K},le
9
radial basis sono costituite da funzioni di base radiale, queste sono delle funzioni a valo-
ri reali che dipendono solo dalla distanza dall’origine o da un valore prefissato. Quindi
(s) = (ksk) oppure (s, c) = (ks ck), dove k · k è l’usuale norma euclidea. Queste
funzioni definiscono una mappatura spaziale che mappa ogni localizzazione s in una nuova
localizzazione f (s) data da:
K
X
f (s) = ci (ks wi k)
i=1
con ci insieme “opportuno” di coefficienti. Le radial basis function sono molte, qualsiasi
funzione tale che (s) = (ksk) definisce una radial basis. Nell’interpolazione spaziale la
nostra scelta per la funzione kernel della base è la thin plate spline (r) = r2 logr dove
r = ks wk. Le condizioni sul comportamento della funzione Z(s) sono le stesse delle basi
cubic splines, ovvero devono esistere continue le derivate parziali seconde, più precisamente
dato s = (x, y):
@2f @2f @2f
9 , , , 2 C2
@x2 @y 2 @x@y
In altre parole devono esistere continue le derivate quarte di Z(s) e quindi assumiamo che la
superficie da interpolare sia piuttosto liscia e regolare. Per definire il grado di “allisciamento”
della superficie interpolata si utilizza la seguente funzione di perdita :
K
X Z Z "✓ ◆2 ✓ ◆2 ✓ ◆2 #
2 @2f @2f @2f
Etps = kZ(si ) f (xi , yi )k + ⇢ +2 + dx dy}
@x2 @x@y @y 2
i=1
10
> require(akima)
> require(fields)
> data(wolfcamp)
> fit.splines <- Tps(wolfcamp$coords, wolfcamp$data)
> out.p <- predict.surface(fit.splines)
> par(mfrow = c(1, 1))
> res.spline <- residuals(fit.splines)
> xy.res <- interp(wolfcamp$coords[, 1], wolfcamp$coords[, 2], res.spline)
> persp(out.p, xlab = "x", ylab = "y", zlab = "z", theta = 60, phi = 30, expand = 0.9,
+ col = "green", ltheta = 120, shade = 0.75, ticktype = "simple", main = "Thin plate spl
+ box = TRUE)
> persp(xy.res$x, xy.res$y, xy.res$z, xlab = "x", ylab = "y", zlab = "z", theta = 60,
+ phi = 30, expand = 0.9, col = "green", ltheta = 120, shade = 0.75, ticktype = "simple"
+ main = "Residuals", box = TRUE)
11
> persp(xy.res$x, xy.res$y, xy.res$z, xlab = "x", ylab = "y", zlab = "z", theta = 60,
+ phi = 30, expand = 0.9, col = "green", ltheta = 120, shade = 0.75, ticktype = "simple"
+ main = "Residuals", box = TRUE)
Residuals
z
Figura 8: Dati wolfcamp, superficie stimata con thin plate splines parte residuale
12
1.2 Modellazione della componente di piccola scala
Per analizzare la componente di piccola scala occorre richiamare il concetto di stazionarietà.
In primo luogo riportiamo la definizione di processo stocastico:
Definizione 1.1 Dato uno spazio di probabilità (⌦, F, P ), un processo stocastico (o processo
aleatorio) con spazio degli stati X è una collezione di variabili aleatorie a valori in X su ⌦
indicizzato da un insieme (discreto o continuo) T . Quindi un processo stocastico Z è una
collezione: {Zt : t 2 T } con Zt (o Z(t)) un insieme di v.a. a valori in X su ⌦.
La legge di probabilità che governa un processo aleatorio è dunque infinito dimensiona-
le, sotto condizioni piuttosto generali è possibile caratterizzare il processo tramite le sue
distribuzioni finito dimensionali. Posto T = R2 ed S ⇢ R2 queste sono:
Fs1 ,...,sn (z1 , . . . , zn ) = P r(Z(s1 ) z1 , . . . , Z(sn ) zn )
Per caratterizzare un processo tramite le sue distribuzioni finito dimensionali occorre il
teorema di estensione di Kolmogorov:
Teorema 1.1 Sia T un qualche intervallo e sia n 2 N. Per ogni k 2 N e ogni sequenza
finita t1 , . . . , tk 2 T , si prenda una sequenza finita ⌫t1 ...tk di misure di probabilità su (Rn )k
. Supponiamo che queste misure soddisfino due condizioni di coerenza:
1. per tutte le permutazioni ⇡ di {1, . . . , k} e insiemi misurabili Fi ✓ Rn ,
⌫t⇡(1) ...t⇡(k) F⇡(1) ⇥ · · · ⇥ F⇡(k) = ⌫t1 ...tk (F1 ⇥ · · · ⇥ Fk )
13
Stazionarietà debole o del secondoR ordine Formalmente, sia {Z(s)} un processo
stocastico 2 Rk , sia µ(s) = E(Z(s) = R Z(s)dF (Z(s)) e C(Z(si ), Z(sj )) = E((Z(si )
µ(si ))(Z(sj ) µ(sj ))). Diremo che il processo Z(s) è debolmente stazionario se
Qualora C(si , sj ) = C(h) con h = khk allora il processo è detto anche isotropico. Si noti
che se il processo è Gaussiano, la stazionarietà debole e la stazionarietà stretta coincidono
essendo il processo interamente caratterizzato dai suoi primi due momenti.
Una terza forma di stazionarietà ancora più debole di quella del secondo ordine si basa sulla
funzione di variogramma (funzione che definiremo qui di seguito):
• E(Z(si ) Z(sj ) = 0
14
3. Una funzione è un semivariogramma se e solo se si tratta di una funzione condi-
zionatamente
PN definita negativa, cioè per qualsiasi sistema di pesi w1 , . . . , wn tali che
i=1 wi = 0 e siti s1 , . . . , sn si ha che:
N X
X N
wi (si , sj )wj 0
i=1 j=1
L’ultima condizione segue dal legame esistente tra variogramma e funzione di cova-
rianza.
Il variogramma teorico è dunque una funzione continua nell’origine, nella pratica spes-
so ci troviamo ad osservare che (0) 6= 0 quando questo accade parliamo di e↵etto
nugget. Tale e↵etto è spesso legato ad errori di misura, problemi di risoluzione spaziale
nel campionamento e cosı̀ via.
Per processi stazionari esiste la seguente relazione tra funzione di covarianza e vario-
gramma:
2 (h) = 2C(0) 2C(h)
per un processo non stazionario invece la relazione è:
Quando un processo non stazionario non ha variabilità spaziale (ovvero C(h) = 0 per
h 6= 0) il semivariogramma è uguale a var(Z(s)) per ogni s 2 S tranne nell’origine.
4. (si , sj ) = E(|Z(si ) Z(sj )|2 ) = (sj , si ) è una funzione simmetrica. Quindi (h) =
( h) è una funzione pari.
15
> curve(Sill - cov.spatial(x, cov.model = cov.model, cov.pars = cov.pars), from = 0,
+ to = 3, xlab = "distance", ylab = "")
> arrows(2, 0, 2, 1, col = 2, code = 3)
> arrows(0, 0.4, 0.8, 0.4, col = 3, code = 3)
> text(0.2, 0.45, "range (=0.8)", col = 3)
> text(2.2, 0.5, "sill (=1)", col = 2)
> curve(cov.spatial(x, cov.model = cov.model, cov.pars = cov.pars), from = 0, to = 3,
+ add = T, col = 4)
> text(0.1, 1, "cov.", col = 4)
> text(0.85, 0.95, "semivari.")
1.0
cov.
semivari.
0.8
0.6
sill (=1)
range (=0.8)
0.4
0.2
0.0
distance
16
Un altro modello di variogramma (e quindi di covarianza) è il modello esponenziale,
questo non ha range finito poiché la sill viene raggiunta solo asintoticamente:
nella pratica utilizzeremo come range finito di questo variogramma la quantità r⇤ = r/3
come indicato da Chiles, Delfiner (1999).
Disegnamo anche questo modello:
17
> curve(sill - cov.spatial(x, cov.model = cov.model, cov.pars = cov.pars), from = 0,
+ to = 3, xlab = "distance", ylab = expression(paste(gamma, "(h)")), col = 1)
> arrows(2, 0, 2, 1, col = "red", code = 3)
> arrows(0, 0.4, 1.3, 0.4, col = "blue", code = 3)
> curve(cov.spatial(x, cov.model = cov.model, cov.pars = cov.pars), from = 0, to = 3,
+ col = 4, add = T)
1.0
0.8
0.6
γ(h)
0.4
0.2
0.0
distance
18
all’ordine d⌫ 1e (b·c è l’intero più grande vicino a ⌫ 1). Quando ⌫ = 0.5 la covarianza
di Matérn coincide con la covarianza esponenziale. Disegnamo questo modello:
19
> cov.model <- "matern"
> phi <- 0.3
> sill <- 1
> nu <- c(0.4, 0.5, 0.6, 0.7, 1)
> cov.pars <- c(sill, phi)
> phi <- 0.3
> sill <- 1
> nu1 <- c(0.4, 0.5, 0.6, 0.7, 1)
> cov.pars <- c(sill, phi)
> curve(cov.spatial(x, cov.model = cov.model, cov.pars = cov.pars, kappa = nu1[1]),
+ from = 0, to = 3, xlab = "distance", ylab = "C(h)", col = 1)
> curve(sill - cov.spatial(x, cov.model = cov.model, cov.pars = cov.pars, kappa = nu1[1]),
+ from = 0, to = 3, xlab = "distance", ylab = "C(h)", col = 1, add = T)
> for (i in 2:5) {
+ curve(cov.spatial(x, cov.model = cov.model, cov.pars = cov.pars, kappa = nu1[i]),
+ from = 0, to = 3, xlab = "distance", ylab = "C(h)", col = i, add = T)
+ curve(sill - cov.spatial(x, cov.model = cov.model, cov.pars = cov.pars, kappa = nu1[i]
+ from = 0, to = 3, xlab = "distance", ylab = "C(h)", col = i, add = T)
+ }
> leg = paste("nu=", nu1)
> legend(2, 0.9, leg, lty = 1, col = c(1:5))
1.0
nu= 0.4
0.8
nu= 0.5
nu= 0.6
nu= 0.7
nu= 1
0.6
C(h)
0.4
0.2
0.0
20
distance
Figura 11: Modello di Matérn: covarianza e variogramma con sill= 1 e range= 0.3 al variare
di ⌫
Metodi di stima del variogramma Dopo aver scelto una famiglia parametrica di
variogrammi quale criterio di adattamento utilizzare ?
• Minimi quadrati (MQ): Sia ˆ (hi ), i = 1, . . . .k una stima non parametrica del vario-
gramma e sia (hi , ✓) un modello di variogramma, allora:
( k )
X
✓ˆM Q = argmin ✓2⇥ (ˆ (hi ) (hi , ✓)) 2
i=1
Questa tecnica di stima assume che V ar(ˆ (hi ) = cost in realtà questa varianza è
2 (h)
proporzionale a |N (h)| , quindi l’assunzione di costanza non è realistica.
Questo è lo stimatore più utilizzato anche perchè, se ˆ (·) è uno stimatore consistente
anche ✓ˆM QG è consistente per ✓ e sotto opportune ipotesi è asintoticamente normale,
cosa che permette di costruire intervalli di confidenza asintotici.
Per poter scegliere una forma parametrica di covarianza abbiamo bisogno che il pro-
cesso sia almeno stazionario del secondo ordine, inoltre se il numero di siti osservati è
elevato, potremmo avere seri problemi computazionali
In pratica i tre approcci sono implementati in R tramite due funzioni: variofit per MQ e
MQG, likfit per la tecnica di massima verosimiglianza. Vediamo un esempio
21
> cov.model = "exponential"
> exvariog <- list(nugget = nugget, kappa = kappa, cov.pars = cov.pars, cov.model = cov.mode
> ols <- variofit(wolf.bin, ini.cov.pars = cov.pars, cov.model = cov.model, fix.nug = TRUE,
+ weights = "equal")
> wls <- variofit(wolf.bin, ini.cov.pars = cov.pars, cov.model = cov.model, fix.nug = TRUE,
+ weights = "cressie")
22
> plot(wolf.bin$u, wolf.bin$v, xlab = "distance", ylab = "semivariance", ylim = c(0,
+ 4600))
> title(main = "Modello esponenziale")
> plot.model.vario(exvariog, distance, add = TRUE)
> lines(ols, col = 2, lty = 2, lwd = 3)
> lines(wls, col = 3, lty = 3, lwd = 4)
> lines(ml, col = 4, lty = 4, lwd = 4)
> legend(150, 2000, c("GR", "MQ", "MQG", "MV"), lty = 1:4, col = 1:4, lwd = 1:4)
Modello esponenziale
●
4000
●
●
●
●
● ● ●
●
● ●
3000
semivariance
●
2000
GR
●
MQ
MQG
1000
MV
0
distance
Figura 12: Stima del modello di variogramma per i dati wolfcamp con trend lineare
La scelta tra i diversi metodi di stima possiamo condurla di nuovo per cross-validation. In
questo caso useremo la funzione xvalid del pacchetto geoR, scegliendo il metodo che mi
restituisce il valore più piccolo del coefficiente di cross validation
> cr.ols = xvalid(wolfcamp, model = ols)
xvalid: number of data locations = 85
xvalid: number of validation locations = 85
23
xvalid: performing cross-validation at location ... 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1
xvalid: end of cross-validation
ols wls ml
1.644411 1.557868 1.131420
Riassumendo
24