Un modo semplice è rasterizzare il dominio di integrazione e calcolare un'approssimazione discreta all'integrale.
Ci sono alcune cose a cui prestare attenzione:
Assicurati di coprire più dell'estensione dei punti: devi includere tutte le posizioni in cui la stima della densità del kernel avrà valori apprezzabili. Ciò significa che è necessario espandere l'estensione dei punti da tre a quattro volte la larghezza di banda del kernel (per un kernel gaussiano).
Il risultato varierà leggermente con la risoluzione del raster. La risoluzione deve essere una piccola frazione della larghezza di banda. Poiché il tempo di calcolo è proporzionale al numero di celle nel raster, non richiede quasi alcun tempo aggiuntivo per eseguire una serie di calcoli utilizzando risoluzioni più grossolane di quella prevista: verificare che i risultati per quelli più grossolani convergano sul risultato per il risoluzione migliore. In caso contrario, potrebbe essere necessaria una risoluzione più fine.
Ecco un'illustrazione per un set di dati di 256 punti:
I punti sono mostrati come punti neri sovrapposti a due stime della densità del kernel. I sei grandi punti rossi sono "sonde" in cui viene valutato l'algoritmo. Questo è stato fatto per quattro larghezze di banda (un valore predefinito compreso tra 1,8 (verticale) e 3 (orizzontale), 1/2, 1 e 5 unità) con una risoluzione di 1000 per 1000 celle. La seguente matrice scatterplot mostra quanto i risultati dipendono dalla larghezza di banda per questi sei punti della sonda, che coprono una vasta gamma di densità:
La variazione si verifica per due motivi. Ovviamente le stime di densità differiscono, introducendo una forma di variazione. Ancora più importante, le differenze nelle stime della densità possono creare grandi differenze in ogni singolo punto ("sonda"). Quest'ultima variazione è maggiore intorno alle "frange" di media densità di gruppi di punti, esattamente quelle posizioni in cui è probabile che questo calcolo venga maggiormente utilizzato.
Ciò dimostra la necessità di una sostanziale cautela nell'uso e nell'interpretazione dei risultati di questi calcoli, poiché possono essere così sensibili a una decisione relativamente arbitraria (la larghezza di banda da utilizzare).
Codice R
L'algoritmo è contenuto nella mezza dozzina di righe della prima funzione f
,. Per illustrarne l'uso, il resto del codice genera le figure precedenti.
library(MASS) # kde2d
library(spatstat) # im class
f <- function(xy, n, x, y, ...) {
#
# Estimate the total where the density does not exceed that at (x,y).
#
# `xy` is a 2 by ... array of points.
# `n` specifies the numbers of rows and columns to use.
# `x` and `y` are coordinates of "probe" points.
# `...` is passed on to `kde2d`.
#
# Returns a list:
# image: a raster of the kernel density
# integral: the estimates at the probe points.
# density: the estimated densities at the probe points.
#
xy.kde <- kde2d(xy[1,], xy[2,], n=n, ...)
xy.im <- im(t(xy.kde$z), xcol=xy.kde$x, yrow=xy.kde$y) # Allows interpolation $
z <- interp.im(xy.im, x, y) # Densities at the probe points
c.0 <- sum(xy.kde$z) # Normalization factor $
i <- sapply(z, function(a) sum(xy.kde$z[xy.kde$z < a])) / c.0
return(list(image=xy.im, integral=i, density=z))
}
#
# Generate data.
#
n <- 256
set.seed(17)
xy <- matrix(c(rnorm(k <- ceiling(2*n * 0.8), mean=c(6,3), sd=c(3/2, 1)),
rnorm(2*n-k, mean=c(2,6), sd=1/2)), nrow=2)
#
# Example of using `f`.
#
y.probe <- 1:6
x.probe <- rep(6, length(y.probe))
lims <- c(min(xy[1,])-15, max(xy[1,])+15, min(xy[2,])-15, max(xy[2,]+15))
ex <- f(xy, 200, x.probe, y.probe, lim=lims)
ex$density; ex$integral
#
# Compare the effects of raster resolution and bandwidth.
#
res <- c(8, 40, 200, 1000)
system.time(
est.0 <- sapply(res,
function(i) f(xy, i, x.probe, y.probe, lims=lims)$integral))
est.0
system.time(
est.1 <- sapply(res,
function(i) f(xy, i, x.probe, y.probe, h=1, lims=lims)$integral))
est.1
system.time(
est.2 <- sapply(res,
function(i) f(xy, i, x.probe, y.probe, h=1/2, lims=lims)$integral))
est.2
system.time(
est.3 <- sapply(res,
function(i) f(xy, i, x.probe, y.probe, h=5, lims=lims)$integral))
est.3
results <- data.frame(Default=est.0[,4], Hp5=est.2[,4],
H1=est.1[,4], H5=est.3[,4])
#
# Compare the integrals at the highest resolution.
#
par(mfrow=c(1,1))
panel <- function(x, y, ...) {
points(x, y)
abline(c(0,1), col="Red")
}
pairs(results, lower.panel=panel)
#
# Display two of the density estimates, the data, and the probe points.
#
par(mfrow=c(1,2))
xy.im <- f(xy, 200, x.probe, y.probe, h=0.5)$image
plot(xy.im, main="Bandwidth=1/2", col=terrain.colors(256))
points(t(xy), pch=".", col="Black")
points(x.probe, y.probe, pch=19, col="Red", cex=.5)
xy.im <- f(xy, 200, x.probe, y.probe, h=5)$image
plot(xy.im, main="Bandwidth=5", col=terrain.colors(256))
points(t(xy), pch=".", col="Black")
points(x.probe, y.probe, pch=19, col="Red", cex=.5)