Uma maneira simples é rasterizar o domínio de integração e calcular uma aproximação discreta à integral.
Há algumas coisas a serem observadas:
Certifique-se de cobrir mais do que a extensão dos pontos: você precisa incluir todos os locais onde a estimativa de densidade do kernel terá valores apreciáveis. Isso significa que você precisa expandir a extensão dos pontos em três a quatro vezes a largura de banda do kernel (para um kernel gaussiano).
O resultado varia um pouco com a resolução da varredura. A resolução precisa ser uma pequena fração da largura de banda. Como o tempo de cálculo é proporcional ao número de células na varredura, não leva quase tempo extra para executar uma série de cálculos usando resoluções mais grossas do que a pretendida: verifique se os resultados para os mais grossos estão convergindo no resultado para o melhor resolução. Caso contrário, uma resolução mais precisa pode ser necessária.
Aqui está uma ilustração para um conjunto de dados de 256 pontos:
Os pontos são mostrados como pontos pretos sobrepostos em duas estimativas de densidade do kernel. Os seis grandes pontos vermelhos são "sondas" nas quais o algoritmo é avaliado. Isso foi feito para quatro larguras de banda (um padrão entre 1,8 (verticalmente) e 3 (horizontalmente), 1/2, 1 e 5 unidades) com uma resolução de 1000 por 1000 células. A seguinte matriz de gráfico de dispersão mostra quão fortemente os resultados dependem da largura de banda para esses seis pontos de sonda, que cobrem uma ampla variedade de densidades:
A variação ocorre por dois motivos. Obviamente, as estimativas de densidade diferem, introduzindo uma forma de variação. Mais importante, as diferenças nas estimativas de densidade podem criar grandes diferenças em qualquer ponto único ("sonda"). A última variação é maior em torno das "franjas" de densidade média de aglomerados de pontos - exatamente nos locais em que esse cálculo provavelmente será mais utilizado.
Isso demonstra a necessidade de cautela substancial no uso e na interpretação dos resultados desses cálculos, porque eles podem ser muito sensíveis a uma decisão relativamente arbitrária (a largura de banda a ser usada).
Código R
O algoritmo está contido na meia dúzia de linhas da primeira função f
,. Para ilustrar seu uso, o restante do código gera as figuras anteriores.
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)