The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
epkde implements the approximate Bayesian method for bandwidth selection in multivariate kernel density estimation (KDE) from Filippone & Sanguinetti (2011). The key idea is to place a prior on the kernel precision matrix \(\Lambda\) (the inverse bandwidth), and use the Expectation Propagation (EP) algorithm to compute an approximate posterior, exploiting a leave-one-out cross-validated likelihood.
Three kernel structures are supported:
| Structure | Prior on \(\Lambda\) | Free parameters |
|---|---|---|
| Isotropic | Gamma on scalar \(\lambda\) | 1 |
| Diagonal | Independent Gammas on \(\lambda_k\) | \(d\) |
| Full | Wishart on matrix \(\Lambda\) | \(d(d+1)/2\) |
The model evidence returned by each fit makes it possible to select the appropriate structure using Bayes factors, without a held-out test set.
# Generate data from a bivariate Gaussian mixture
n <- 150; d <- 2
x <- rbind(matrix(rnorm(n/2 * d, mean = c(-2, 0)), ncol = d),
matrix(rnorm(n/2 * d, mean = c( 2, 0)), ncol = d))fit_diag <- ep_kde_diagonal(x,
prior_shape = rep(1, d),
prior_rate = rep(1, d))
cat("Posterior mean precision per dimension:",
fit_diag$post_shape / fit_diag$post_rate, "\n")
#> Posterior mean precision per dimension: 2.28161 2.224204
cat("Log model evidence:", fit_diag$log_evidence, "\n")
#> Log model evidence: -590.5628fit_full <- ep_kde_full(x, prior_nu = 0)
cat("Posterior nu:", fit_full$post_nu, "\n")
#> Posterior nu: 131.6236
cat("Posterior mean precision matrix:\n")
#> Posterior mean precision matrix:
print(fit_full$post_mean)
#> [,1] [,2]
#> [1,] 0.0921679865 -0.0002349248
#> [2,] -0.0002349248 0.0906878646
cat("Log model evidence:", fit_full$log_evidence, "\n")
#> Log model evidence: -799.2478ev <- c(isotropic = model_evidence(fit_iso),
diagonal = model_evidence(fit_diag),
full = model_evidence(fit_full))
cat("Log evidences:\n"); print(ev)
#> Log evidences:
#> isotropic diagonal full
#> -589.3180 -590.5628 -799.2478
cat("\nLog Bayes factor (diagonal vs. isotropic):",
ev["diagonal"] - ev["isotropic"], "\n")
#>
#> Log Bayes factor (diagonal vs. isotropic): -1.244776# Grid for evaluation
gr <- seq(-6, 6, length.out = 50)
grid <- as.matrix(expand.grid(gr, gr))
# Use the diagonal fit: Lambda = diag(post_shape / post_rate)
Lambda_diag <- diag(fit_diag$post_shape / fit_diag$post_rate)
p_hat <- kde_predict(grid, x, Lambda_diag)
# Contour plot
contour(gr, gr, matrix(p_hat, 50),
main = "Bayesian KDE (diagonal bandwidth)",
xlab = expression(x[1]), ylab = expression(x[2]))
points(x, pch = 20, cex = 0.4)The isotropic model supports sequential updates: after fitting on an initial batch, you can incorporate new observations cheaply without reprocessing the original data.
n_init <- 100
x_init <- x[1:n_init, ]
x_more <- x[(n_init + 1):n, ]
fit_init <- ep_kde_isotropic(x_init, prior_shape = 1, prior_rate = 1)
fit_update <- ep_kde_online(x_init, x_more,
prior_shape = 1, prior_rate = 1,
fit_old = fit_init)
fit_all <- ep_kde_isotropic(x, prior_shape = 1, prior_rate = 1)
cat("Online posterior mean precision :", fit_update$post_shape / fit_update$post_rate, "\n")
#> Online posterior mean precision : 2.323879
cat("Offline (all-at-once) mean prec :", fit_all$post_shape / fit_all$post_rate, "\n")
#> Offline (all-at-once) mean prec : 2.316491Filippone, M. & Sanguinetti, G. (2011). Approximate inference of the bandwidth in multivariate kernel density estimation. Computational Statistics & Data Analysis, 55(12), 3104–3122. https://doi.org/10.1016/j.csda.2011.05.023
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.