proxymix proxymix logo

Lifecycle: experimental CRAN status R-CMD-check Codecov test coverage r-universe pkgdown

proxymix fits multivariate Gaussian-mixture proxies to target distributions on \(\mathbb{R}^p\). Three regimes from van der Hoek and Elliott (2024) fit a density or samples and are Kullback–Leibler optimal. A fourth fits a distribution known only through its characteristic function. All four are unified under one verb:

Regime When it applies Method
(i) moment \(N = 1\) component Closed-form moment matching
(ii) sample i.i.d. samples from the target are available Classical EM
(iii) kld target density f(x) can be evaluated but not (cheaply) sampled KLD-EM with importance sampling
(iv) cf only the characteristic function of the target is known Least squares on the characteristic function, with bounds on the Kolmogorov distance

Regime (iii) is the reason the package exists. The sample-based mixture packages (mclust, mixtools, flexmix) all assume i.i.d. draws from the target; proxymix fits directly against an evaluable (possibly unnormalised) log-density. The nearest CRAN neighbour is AdMit, which adaptively fits a mixture of Student-t distributions to an evaluable kernel as an importance/proposal density; proxymix differs in fitting a Gaussian mixture that is Kullback–Leibler optimal, precisely so that the fitted object then supports the closed-form operator calculus (marginals, conditionals, Bayes updates, products, convolutions, filtering) and carries a fit-quality certificate through every operation.

Why not MCMC? If you can evaluate the unnormalised density you can always run a sampler and then fit a mixture to the draws. The regime-(iii) fit is the shortcut when what you want is the compact closed-form object: no chain tuning or convergence diagnostics, a deterministic pipeline given the seed, and a mixture whose marginals, conditionals, moments and samples are then available in closed form through the operator calculus. The trade-off is dimension: the importance sampling that drives regime (iii) loses effective sample size sharply beyond roughly \(p = 5\)–\(10\), and every fit reports its effective sample size so that limit is visible rather than silent. For high-dimensional posteriors, sample with your favourite MCMC and use regime (ii) on the draws.

mclust and mixtools fit to draws from the target. proxymix also fits to a density it can only evaluate, and its Gaussian components keep marginals, conditionals and Bayes updates in closed form.

Installation

From CRAN:

install.packages("proxymix")

The development version from GitHub:

# install.packages("remotes")
remotes::install_github("max578/proxymix")

or locally from the source tree:

R CMD build proxymix
R CMD INSTALL proxymix_*.tar.gz

Documentation site: https://max578.github.io/proxymix/.

Quick start

library(proxymix)

## A target you can evaluate but not sample from -- a 2D "banana".
banana <- banana_target()

## Fit a 3-component Gaussian mixture proxy via KLD-EM with importance sampling.
fit <- fit_proxymix(banana, N = 3L, regime = "kld",
                    proposal = proposal_mvt(n_dim = 2L, df = 5),
                    is_size = 2000L, max_iter = 60L, seed = 1L)

print(fit)
#> <gmm_fit>: regime = "kld", K = 3, p = 2
#>   target     : banana
#>   iterations : 37
#>   converged  : TRUE
#>   [1] w = 0.6456, |mu| = 0.3299, tr(Sigma) = 1.3601
#>   [2] w = 0.2473, |mu| = 1.2996, tr(Sigma) = 2.2312
#>   [3] w = 0.1071, |mu| = 1.8882, tr(Sigma) = 4.9044

## Closed-form operations on the fitted mixture.
gmm_marginalise(fit, keep = 1L)
#> <marginalise(kld_em[N=3] on banana)>: K = 3 components in p = 1 dimensions
#>   [1] w = 0.6456, |mu| = 0.1818, tr(Sigma) = 0.4620
#>   [2] w = 0.2473, |mu| = 1.1518, tr(Sigma) = 0.4846
#>   [3] w = 0.1071, |mu| = 1.5954, tr(Sigma) = 0.6321
gmm_conditionalise(fit, given = c(NA, 0.5))
#> <conditionalise(kld_em[N=3] on banana)>: K = 3 components in p = 1 dimensions
#>   [1] w = 0.6730, |mu| = 0.2620, tr(Sigma) = 0.4524
#>   [2] w = 0.2576, |mu| = 1.1133, tr(Sigma) = 0.2352
#>   [3] w = 0.0694, |mu| = 1.4188, tr(Sigma) = 0.1199

A distribution known only through its characteristic function

## The symmetric stable law of index 1.5 has no closed-form density
## and infinite variance, but its characteristic function is exp(-|t|^1.5).
cf_stable <- function(t) exp(-abs(t[, 1])^1.5)
fit_stable <- from_cf_elliptical(cf_stable, n_dim = 1L, seed = 1L)
fit_stable
#> <gmm_fit>: regime = "cf", K = 10, p = 1
#>   target     : <none>
#>   iterations : NA
#>   converged  : TRUE
#>   cf held-out RMS error : 0.000557
#>   Kolmogorov distance   : at least 0.000245, at most 0.00509 (1 direction)
#>   [1] w = 0.5595, |mu| = 0.0000, tr(Sigma) = 1.3211
#>   [2] w = 0.2645, |mu| = 0.0000, tr(Sigma) = 3.7563
#>   [3] w = 0.0618, |mu| = 0.0000, tr(Sigma) = 10.6806
#>   [4] w = 0.0500, |mu| = 0.0000, tr(Sigma) = 30.3689
#>   [5] w = 0.0478, |mu| = 0.0000, tr(Sigma) = 0.4646
#>   ... 5 more components

## Quantiles, tail probabilities and draws come from the mixture.
qgmm(c(0.95, 0.99), fit_stable)
#> [1] 3.048049 7.752634

The printed bounds say how far the distribution function of the mixture can be from that of the stable law. The vignette on characteristic functions checks them against an exact computation.

The unified fitting verb

fit_proxymix(
  target,
  N        = 1L,
  regime   = c("auto", "moment", "sample", "kld", "cf"),
  ...
)

Closed-form mixture operators

dgmm(x, fit)              # density evaluation
rgmm(n, fit)              # exact sampling
gmm_marginalise(fit, keep)
gmm_conditionalise(fit, given)
gmm_kld(fit_p, fit_q)     # Monte Carlo + variational bounds

Mapping the optima of an objective

fit   <- from_objective(f, lower, upper, N = 10L)  # a mixture map of the optima
gmm_modes(fit)$modes                               # the distinct optima

from_objective() treats an objective f as the Gibbs measure exp(-f / T) – a regime-(iii) target you can evaluate but not sample – and returns a closed-form mixture over its low regions, so a multimodal f is recovered as a whole rather than one optimum at a time. gmm_modes() resolves the fitted map into the recovered optima.

Which function do I need?

You have You want Reach for
an evaluable (unnormalised) log-density a compact closed-form proxy gmm_target() then fit_proxymix(regime = "kld")
i.i.d. samples a mixture fit gmm_target_from_samples() then fit_proxymix()
an objective function a map of its optima from_objective(), gmm_modes()
a kernel density estimate a small closed-form surrogate from_kde()
a characteristic function only (a stable law, a sum of independent variables) a mixture with bounds on the Kolmogorov distance cf_target() then fit_proxymix(), or from_cf(), from_cf_elliptical(), from_cf_sources()
a fitted mixture marginals, conditionals, updates gmm_marginalise(), gmm_conditionalise(), gmm_observe(), gmm_affine()
data with holes multiple imputation gmm_impute() with mar() / mnar() / censored()
a time series + state-space model filtering / stability testing gmm_filter(), gmm_eos_test()
a fitted mixture information-theoretic diagnostics gmm_entropy(), gmm_divergence(), gmm_mutual_information()
a fitted mixture + treatment data causal / decision quantities gmm_intervene(), fit_uplift(), proxy_cate()
an unnormalised posterior the marginal likelihood gmm_evidence()
a fitted proxy error bars on any functional gmm_fit_ensemble(), proxy_functional_ci()
an evaluable-only target the component count select_N()
a fit collapsing in high dimension an adaptive proposal fit_kld_em(adapt = "pmc")

Vignettes

The package ships with thirteen vignettes:

Interactive tutorial

A standalone, single-file HTML primer for proxymix is hosted at

https://max578.github.io/proxymix-tutorial/

The page is targeted at Adelaide University Mathematics and Statistics undergraduates (Guided depth, default) and postgraduate / PhD readers (Technical depth, via the in-page dial). It runs in the browser with no R install required, and works the same way offline by double-click. Source at max578/proxymix-tutorial.

Reference

Hoek, J. van der and Elliott, R. J. (2024). Mixtures of multivariate Gaussians. Stochastic Analysis and Applications. doi:10.1080/07362994.2024.2372605.

Contributing

Bug reports and suggestions are welcome through the GitHub issues.

Citation

citation("proxymix")

Licence

MIT © Max Moldovan.