| Title: | KL-Optimal Gaussian Mixture Proxies for Arbitrary Target Densities |
|---|---|
| Description: | Fits multivariate Gaussian-mixture proxies that are Kullback-Leibler optimal to user-supplied target densities on real Euclidean space. Three fitting regimes are unified under one verb: (i) closed-form moment matching for a single component, (ii) classical expectation-maximisation when independent samples are available, and (iii) importance-sampled KLD-EM when the target can be evaluated point-wise but not (cheaply) sampled. Closed-form Gaussian-mixture operators (density, sampling, marginalisation, conditioning, divergence) round out the toolkit. The conditioning operator drives multiple imputation of data missing at random, covering the multimodal and heteroscedastic cases a single-Gaussian model cannot represent. Implements the regime hierarchy of Hoek and Elliott (2024) <doi:10.1080/07362994.2024.2372605>. |
| Authors: | Max Moldovan [aut, cre] (ORCID: <https://orcid.org/0000-0001-9680-8474>) |
| Maintainer: | Max Moldovan <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.15.1 |
| Built: | 2026-07-05 13:24:27 UTC |
| Source: | https://github.com/max578/proxymix |
Packages a gmm_imputation as a mice::mids object so that an arbitrary
model estimand can be fitted and pooled with the established mice workflow.
The joint Gaussian-mixture imputations – including the multimodal and
heteroscedastic shapes a univariate imputer cannot produce – flow through
unchanged; mice supplies with(), mice::pool(), and the pooled
diagnostics.
as_mids(object)as_mids(object)
object |
A mice::mids object with m imputations.
gmm_impute(), proxy_pool() for the closed-form column-mean
pooling.
Other imputation:
gmm_complete(),
gmm_imputation(),
gmm_impute(),
mechanism,
proxy_fmi(),
proxy_mnar_sensitivity(),
proxy_pool()
set.seed(1) x1 <- rnorm(150); x2 <- x1 + rnorm(150) x2[runif(150) < 0.3] <- NA imp <- gmm_impute(cbind(x1, x2), N = 1L, m = 10L, seed = 1L) if (requireNamespace("mice", quietly = TRUE)) { fit <- with(as_mids(imp), lm(x2 ~ x1)) summary(mice::pool(fit)) }set.seed(1) x1 <- rnorm(150); x2 <- x1 + rnorm(150) x2[runif(150) < 0.3] <- NA imp <- gmm_impute(cbind(x1, x2), N = 1L, m = 10L, seed = 1L) if (requireNamespace("mice", quietly = TRUE)) { fit <- with(as_mids(imp), lm(x2 ~ x1)) summary(mice::pool(fit)) }
An autoplot() method for gmm_fit objects, rendering the fitted mixture
with ggplot2. The displayed coordinates are reduced to the requested one
or two dimensions through the closed-form marginal gmm_marginalise(), so
the method works for a proxy of any ambient dimension p.
A one-dimensional request draws the marginal mixture density, optionally with the per-component densities underneath and a rug of the target's samples. A two-dimensional request draws the marginal density as a viridis raster with white contour lines, optionally overlaying each component's mean and a probability-contour ellipse.
object |
A gmm_fit, typically from |
dims |
Integer vector of length one or two giving the coordinate(s) to
display, in |
n_grid |
Integer scalar — the number of grid points per axis at which
the density is evaluated. A two-dimensional plot evaluates |
n_sd |
Numeric scalar — how many component standard deviations beyond the extreme component means the plotting window extends. |
level |
Numeric scalar in |
show_components |
Logical scalar — whether to overlay the per-component densities (one dimension) or mean-and-ellipse glyphs (two dimensions). |
show_data |
Logical scalar — whether to overlay the target's samples, when the fitted target carries any. |
... |
Currently ignored, present for generic compatibility. |
The method is registered against the ggplot2::autoplot() generic only
when ggplot2 is installed; call it as ggplot2::autoplot(fit) or load
ggplot2 first. It returns the ggplot object, so the usual + layering
applies for further customisation.
A ggplot object.
Other classes:
glance.gmm_fit,
gmm(),
gmm_counterfactual_law(),
gmm_dim(),
gmm_fit(),
gmm_n_components(),
gmm_target(),
gmm_weights(),
is_proposal(),
tidy.gmm
samples <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(samples) fit <- fit_proxymix(tgt, N = 2L, regime = "sample", max_iter = 25L) ggplot2::autoplot(fit) ggplot2::autoplot(fit, dims = 1L)samples <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(samples) fit <- fit_proxymix(tgt, N = 2L, regime = "sample", max_iter = 25L) ggplot2::autoplot(fit) ggplot2::autoplot(fit, dims = 1L)
A 2-D "banana" density obtained by warping an isotropic Gaussian
through the map .
The map has unit Jacobian, so the resulting density is exactly normalised.
banana_target(with_samples = FALSE, n = 2000L, seed = 1L)banana_target(with_samples = FALSE, n = 2000L, seed = 1L)
with_samples |
If |
n |
Number of samples to attach when |
seed |
Optional integer seed used when drawing the samples. |
A gmm_target in dimension 2.
Other targets:
donut_target(),
epanechnikov_target(),
gmm_target_from_samples(),
maxent_target(),
mixture_target()
b <- banana_target() b b@log_density(matrix(c(0, 0, 1, 0), ncol = 2, byrow = TRUE))b <- banana_target() b b@log_density(matrix(c(0, 0, 1, 0), ncol = 2, byrow = TRUE))
Returns the Bayesian and Akaike information criteria of a regime-(ii) fit,
together with the integrated completed likelihood (ICL). All three are
computed against the empirical log-likelihood of the samples used to fit
the model and are reported on the same scale (smaller is better). They are
NA for regimes that do not have an empirical likelihood ("moment",
"kld").
bic_aic(fit)bic_aic(fit)
fit |
A gmm_fit. |
The ICL of Biernacki, Celeux and Govaert (2000) adds to the BIC twice the
entropy of the fitted classification,
, where
is the entropy of
the responsibilities . It therefore penalises mixtures whose
components overlap (uncertain assignments), and favours well-separated
clustering solutions over the merely best-fitting ones. Because
, the ICL is never smaller than the BIC, and the two coincide
for a single component (), where every responsibility is one. The
classification entropy itself is returned as classification_entropy.
A list with bic, aic, icl, classification_entropy, and
n_params.
Biernacki, C., Celeux, G. and Govaert, G. (2000) Assessing a mixture model for clustering with the integrated completed likelihood. IEEE Transactions on Pattern Analysis and Machine Intelligence 22(7), 719–725. doi:10.1109/34.865189
Other diagnostics:
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
x <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(x) fit <- fit_proxymix(tgt, N = 2L, regime = "sample", max_iter = 25L) bic_aic(fit)x <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(x) fit <- fit_proxymix(tgt, N = 2L, regime = "sample", max_iter = 25L) bic_aic(fit)
Evaluates the density (or log-density) of a Gaussian mixture at one or more points.
dgmm(x, g, log = FALSE)dgmm(x, g, log = FALSE)
x |
A numeric matrix with one observation per row, or a length- |
g |
|
log |
Logical. If |
A numeric vector of length nrow(x).
Other ops:
gmm_canonicalise(),
gmm_conditionalise(),
gmm_divergence(),
gmm_kld(),
gmm_marginalise(),
gmm_mean(),
gmm_modes(),
pgmm(),
rgmm()
g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) dgmm(c(0, 0), g) dgmm(c(0, 0), g, log = TRUE)g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) dgmm(c(0, 0), g) dgmm(c(0, 0), g, log = TRUE)
A rotationally symmetric annulus on , with density
Numerical integration in polar coordinates fixes the normaliser; the
returned target exposes a normalised log_density.
donut_target(r0 = 2.5, sigma = 0.5, with_samples = FALSE, n = 2000L, seed = 1L)donut_target(r0 = 2.5, sigma = 0.5, with_samples = FALSE, n = 2000L, seed = 1L)
r0 |
Centre radius of the annulus. |
sigma |
Annulus width. |
with_samples |
If |
n |
Number of samples to attach when |
seed |
Optional integer seed used when drawing the samples. |
A gmm_target in dimension 2.
Other targets:
banana_target(),
epanechnikov_target(),
gmm_target_from_samples(),
maxent_target(),
mixture_target()
d <- donut_target() dd <- donut_target() d
The canonical compact-support target: a product of one-dimensional
Epanechnikov densities
, rescaled to
[center - half_width, center + half_width] in each coordinate. No mixture
of full-support Gaussians can have compact support, so this target is the
clean case where regime (iii) is the only viable fitting route. It declares
its support, which makes fit_kld_em() (and fit_proxymix() with
regime = "kld") select a support-matched uniform proposal automatically
instead of the default multivariate-t, which would place importance mass
where the log-density is -Inf.
epanechnikov_target( n_dim = 1L, center = 0, half_width = 1, with_samples = FALSE, n = 2000L, seed = 1L )epanechnikov_target( n_dim = 1L, center = 0, half_width = 1, with_samples = FALSE, n = 2000L, seed = 1L )
n_dim |
Ambient dimension |
center |
Length-1 (recycled) or length- |
half_width |
Length-1 (recycled) or length- |
with_samples |
If |
n |
Number of samples to attach when |
seed |
Optional integer seed used when drawing the samples. |
A gmm_target in dimension n_dim with a declared compact
support.
Other targets:
banana_target(),
donut_target(),
gmm_target_from_samples(),
maxent_target(),
mixture_target()
e <- epanechnikov_target() e e@log_density(matrix(c(0, 0.5, 1.5), ncol = 1L)) # finite, finite, -Infe <- epanechnikov_target() e e@log_density(matrix(c(0, 0.5, 1.5), ncol = 1L)) # finite, finite, -Inf
Convenience accessor returning the headline IS-quality numbers for a
regime-(iii) fit: effective sample size and its ratio to is_size,
the largest self-normalised weight, the support fraction (proportion
of draws that received a finite weight), and the Monte-Carlo standard
error of the final KLD estimate. Returns NA fields for regimes that
do not use importance sampling.
ess_summary(fit)ess_summary(fit)
fit |
A gmm_fit. |
Validation-side numbers (validation_*) are populated only when the
fit was called with validation_size > 0.
A list of numeric scalars (or NAs where not applicable).
Other diagnostics:
bic_aic(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
fit <- fit_proxymix(banana_target(), N = 3L, regime = "kld", is_size = 1500L, max_iter = 20L, seed = 1L, validation_size = 1500L) ess_summary(fit)fit <- fit_proxymix(banana_target(), N = 3L, regime = "kld", is_size = 1500L, max_iter = 20L, seed = 1L, validation_size = 1500L) ess_summary(fit)
Returns the effective sample size (1 / sum(W^2)) of the
self-normalised importance weights used by a regime-(iii) fit. NA for
regimes that do not use importance sampling.
ess_trace(fit)ess_trace(fit)
fit |
A gmm_fit. |
Numeric scalar (or NA_real_).
Other diagnostics:
bic_aic(),
ess_summary(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1000L, max_iter = 15L, seed = 1L) ess_trace(fit)fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1000L, max_iter = 15L, seed = 1L) ess_trace(fit)
Implements regime (ii) of Hoek and Elliott (2024). Runs the textbook expectation-maximisation algorithm for Gaussian mixtures on the supplied samples, with diagonal ridge regularisation for numerical stability, optional multi-start, and monotone-log-likelihood checking.
fit_em_samples( target, N = 2L, init = NULL, max_iter = 100L, tol = 1e-06, ridge_eps = 1e-06, n_starts = 5L, anneal = FALSE, temp_schedule = NULL, seed = NULL, canonicalise = TRUE )fit_em_samples( target, N = 2L, init = NULL, max_iter = 100L, tol = 1e-06, ridge_eps = 1e-06, n_starts = 5L, anneal = FALSE, temp_schedule = NULL, seed = NULL, canonicalise = TRUE )
target |
A gmm_target carrying an |
N |
Number of mixture components. |
init |
A gmm initialisation, or |
max_iter |
Maximum number of EM iterations. |
tol |
Relative-log-likelihood convergence tolerance. |
ridge_eps |
Ridge added to each component covariance at every M-step. |
n_starts |
Number of multi-start initialisations (only when |
anneal |
Logical. If |
temp_schedule |
Optional numeric vector of descending temperatures for
the annealing warm-start. |
seed |
Optional integer seed for the annealing perturbations (the
warm-start is deterministic given a seed). Ignored when |
canonicalise |
Logical. If |
A gmm_fit with regime = "sample". When anneal = TRUE the
diagnostics list also carries annealed = TRUE and the temp_schedule
used.
Other fitting:
fit_kld_em(),
fit_moment_match(),
from_kde(),
from_objective(),
select_N()
x <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(x) fit <- fit_em_samples(tgt, N = 2L, max_iter = 30L, n_starts = 2L) fit@diagnostics$loglik_finalx <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(x) fit <- fit_em_samples(tgt, N = 2L, max_iter = 30L, n_starts = 2L) fit@diagnostics$loglik_final
Implements regime (iii) of Hoek and Elliott (2024). Minimises
KL(f || g_theta) where f is supplied as an evaluable log-density on
the target, via expectation-maximisation against importance-sampled
draws from a user-chosen proposal q.
fit_kld_em( target, N = 3L, proposal = NULL, is_size = 5000L, init = NULL, max_iter = 100L, tol = 1e-05, ridge_eps = 1e-06, min_ess = 50, on_low_ess = c("warn", "abort"), seed = NULL, validation_size = NULL, validation_proposal = NULL, validation_seed = NULL, support_warn = TRUE, adapt = c("none", "pmc"), refresh_every = 5L, defensive_gamma = 0.15, inflate = 1.5, anneal = FALSE, temp_schedule = NULL, canonicalise = TRUE )fit_kld_em( target, N = 3L, proposal = NULL, is_size = 5000L, init = NULL, max_iter = 100L, tol = 1e-05, ridge_eps = 1e-06, min_ess = 50, on_low_ess = c("warn", "abort"), seed = NULL, validation_size = NULL, validation_proposal = NULL, validation_seed = NULL, support_warn = TRUE, adapt = c("none", "pmc"), refresh_every = 5L, defensive_gamma = 0.15, inflate = 1.5, anneal = FALSE, temp_schedule = NULL, canonicalise = TRUE )
target |
A gmm_target with a non-NULL |
N |
Number of mixture components. |
proposal |
An is_proposal. When |
is_size |
Number of importance-sampling draws used for fitting. |
init |
A gmm initialisation, or |
max_iter |
Maximum number of EM iterations. |
tol |
Convergence tolerance on the relative change in the
importance-weighted EM objective |
ridge_eps |
Ridge added to each component covariance at every M-step. |
min_ess |
Minimum effective sample size below which the fit is
flagged as degenerate: a classed warning ( |
on_low_ess |
What to do when the effective sample size falls below
|
seed |
Optional integer seed. When supplied, the fit is
reproducible end-to-end: the fitting IS draw, the initialisation
resample and kmeans pass, and any empty-component reseed draws are
all derived from it. When |
validation_size |
Number of independent importance-sampling draws
to use for held-out validation. The default |
validation_proposal |
Optional is_proposal for the validation sample. Defaults to the same proposal used for fitting. |
validation_seed |
Optional integer seed used when drawing the
validation sample. Defaults to |
support_warn |
Logical. If |
adapt |
Proposal adaptation: |
refresh_every |
With |
defensive_gamma |
With |
inflate |
With |
anneal |
Logical. If |
temp_schedule |
Optional numeric vector of descending temperatures for
the annealing warm-start. |
canonicalise |
Logical. If |
With adapt = "none" (the default) the Monte Carlo draws from q are
computed once at the start and the resulting self-normalised
importance-sampling weights are reused at every EM iteration. With
adapt = "pmc" the proposal is refreshed every refresh_every
iterations with a defensive mixture built from the current iterate –
the population-Monte-Carlo scheme: the fitted mixture (covariances
inflated by inflate) carries 1 - defensive_gamma of the proposal
mass and the original proposal q keeps defensive_gamma as a
heavy-tailed anchor, a fresh IS batch is drawn, and EM continues on the
refreshed weights. Because the refreshed proposal tracks the target,
the effective sample size recovers from a poor initial proposal and the
usable dimension range extends well beyond what a fixed proposal
reaches; the per-batch ESS trace is reported as
diagnostics$ess_history. While a batch is degenerate (its effective
sample size is below min_ess), the refresh fires every iteration
with an escalating covariance inflation floored at a growing fraction
of the batch's sample covariance, so a collapsed iterate walks back
out toward the target instead of freezing; and convergence is only
accepted on an adapted batch, so a run that stabilises on the original
proposal's draw is refreshed at least once before it is allowed to
stop. The scheme is the mixture population-Monte-Carlo idea of Cappé
et al. (2008) with the defensive-mixture safeguard of Owen and Zhou
(2000); it re-draws rather than recycles batches (compare the adaptive
multiple importance sampling of Cornuet et al., 2012).
Since v0.1.1 the function also draws an independent validation IS
sample when validation_size > 0 and reports its own KLD estimate,
effective sample size, and largest weight share. This lets users tell
the difference between in-sample EM overfit to one particular IS draw
and a fit that generalises across independent IS draws.
When the target's normalised property is FALSE or NA, the
importance-sampled kld_final and kld_trace measure
rather than the absolute
divergence. The fit's diagnostics list records this via
kld_is_shifted = TRUE and a kld_shift_explanation string. When the
target also supplies a finite log_normalizer, a corrected absolute
estimate is reported as kld_final_absolute.
A gmm_fit with regime = "kld". The diagnostics list
contains, among others, kld_trace, kld_final,
kld_is_shifted, kld_final_absolute (when computable), ess,
ess_relative (ess / is_size), max_weight, support_fraction,
mc_se_kld, validation_kld, validation_ess, and
validation_max_weight.
Cappé, O., Douc, R., Guillin, A., Marin, J.-M. and Robert, C. P. (2008) Adaptive importance sampling in general mixture classes. Statistics and Computing 18, 447–459. doi:10.1007/s11222-008-9059-x
Cornuet, J.-M., Marin, J.-M., Mira, A. and Robert, C. P. (2012) Adaptive multiple importance sampling. Scandinavian Journal of Statistics 39, 798–812. doi:10.1111/j.1467-9469.2011.00756.x
Owen, A. and Zhou, Y. (2000) Safe and effective importance sampling. Journal of the American Statistical Association 95(449), 135–143. doi:10.1080/01621459.2000.10473909
Other fitting:
fit_em_samples(),
fit_moment_match(),
from_kde(),
from_objective(),
select_N()
tgt <- banana_target() q <- is_mvt(n_dim = 2L, mean = c(0, 0), sigma = 4 * diag(2), df = 5) fit <- fit_kld_em(tgt, N = 3L, proposal = q, is_size = 1500L, max_iter = 25L, seed = 1L, validation_size = 1500L) fit@diagnostics$kld_final fit@diagnostics$validation_kldtgt <- banana_target() q <- is_mvt(n_dim = 2L, mean = c(0, 0), sigma = 4 * diag(2), df = 5) fit <- fit_kld_em(tgt, N = 3L, proposal = q, is_size = 1500L, max_iter = 25L, seed = 1L, validation_size = 1500L) fit@diagnostics$kld_final fit@diagnostics$validation_kld
Implements regime (i) of Hoek and Elliott (2024). When N == 1, this is
the exact moment match: mu is the target mean and Sigma is the target
covariance. When N > 1, the function returns the deterministic
moment-seed of init_moment_seed() wrapped as a gmm_fit, without
iterative refinement — useful as a starting point for the iterative
regimes.
fit_moment_match(target, N = 1L, ridge_eps = 1e-06, canonicalise = TRUE)fit_moment_match(target, N = 1L, ridge_eps = 1e-06, canonicalise = TRUE)
target |
A gmm_target. |
N |
Number of components. |
ridge_eps |
Ridge added to the empirical covariance for numerical stability. |
canonicalise |
Logical. If |
Either the target must carry an n by p samples matrix, or its
metadata slot must contain pre-computed moments of the form
list(mean = <p-vec>, cov = <p-by-p>).
A gmm_fit with regime = "moment".
Other fitting:
fit_em_samples(),
fit_kld_em(),
from_kde(),
from_objective(),
select_N()
x <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(x) fit_moment_match(tgt, N = 1L)x <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(x) fit_moment_match(tgt, N = 1L)
The unified front door of proxymix. Picks a fitting regime (or honours
an explicit choice) and dispatches to the corresponding regime-specific
fitter:
fit_proxymix( target, N = 1L, regime = c("auto", "moment", "sample", "kld"), ... )fit_proxymix( target, N = 1L, regime = c("auto", "moment", "sample", "kld"), ... )
target |
A gmm_target. |
N |
Number of components. |
regime |
One of |
... |
Additional arguments forwarded to the regime-specific fitter.
The most useful pass-throughs are |
"moment" - closed-form moment matching (fit_moment_match()).
"sample" - classical EM on i.i.d. samples (fit_em_samples()).
"kld" - importance-sampled KLD-EM (fit_kld_em()) for a target
that can be evaluated but not sampled.
With regime = "auto" the choice is made from the shape of the supplied
target:
N == 1 and the target carries samples or moments: "moment".
N >= 2 and the target carries samples: "sample".
The target carries log_density only (no samples): "kld".
A gmm_fit.
## auto: samples + N=2 -> classical EM. x <- matrix(stats::rnorm(200), ncol = 2) tgt_s <- gmm_target_from_samples(x) fit_proxymix(tgt_s, N = 2L, max_iter = 25L) ## explicit "kld" on a log-density-only target. fit_proxymix(banana_target(), N = 3L, regime = "kld", is_size = 1000L, max_iter = 20L, seed = 1L)## auto: samples + N=2 -> classical EM. x <- matrix(stats::rnorm(200), ncol = 2) tgt_s <- gmm_target_from_samples(x) fit_proxymix(tgt_s, N = 2L, max_iter = 25L) ## explicit "kld" on a log-density-only target. fit_proxymix(banana_target(), N = 3L, regime = "kld", is_size = 1000L, max_iter = 20L, seed = 1L)
Assembles a joint Gaussian-mixture proxy over the outcome, the treatment,
and the covariates, and returns an uplift_model that the decision verbs
read in closed form. One fit yields prediction, heterogeneous treatment
effects, optimal actions, off-line policy value, and an identification
audit – see proxy_cate(), proxy_decide(), proxy_policy_value() and
proxy_identification_report().
fit_uplift( data, outcome, treatment, covariates, N = "auto", regime = "auto", assume = c("ignorability", "latent_confounder"), outcome_type = c("continuous", "binary", "count"), n_grid = 1:4, seed = NULL, ... )fit_uplift( data, outcome, treatment, covariates, N = "auto", regime = "auto", assume = c("ignorability", "latent_confounder"), outcome_type = c("continuous", "binary", "count"), n_grid = 1:4, seed = NULL, ... )
data |
A data frame holding the outcome, treatment and covariate columns. |
outcome |
A single column name – the outcome |
treatment |
A single column name – the binary treatment |
covariates |
A character vector of one or more column names – the
pre-treatment covariates |
N |
Number of mixture components, or |
regime |
One of |
assume |
One of |
outcome_type |
One of |
n_grid |
Integer vector of candidate component counts used when
|
seed |
Optional integer. When supplied, the fitting (including any random EM starts) runs under a fixed seed and the global RNG state is restored on exit, so the fit is reproducible without disturbing the caller's stream. |
... |
Additional arguments forwarded to |
The component count N may be fixed or chosen automatically. With
N = "auto" the function sweeps n_grid and keeps the K that minimises the
joint BIC; the full BIC trace is stored in the model's metadata. The
treatment is binary at this version ({t0, t1}); a continuous dose is a
future extension.
An uplift_model.
proxy_cate(), proxy_decide(), proxy_identification_report()
Other decision:
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) n <- 400L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + 0.5 * x + (1 + x) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, outcome = "y", treatment = "t", covariates = "x", N = 2L, regime = "sample", max_iter = 50L, seed = 1L) mset.seed(1) n <- 400L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + 0.5 * x + (1 + x) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, outcome = "y", treatment = "t", covariates = "x", N = 2L, regime = "sample", max_iter = 50L, seed = 1L) m
Fits an N-component Gaussian-mixture proxy to a (Gaussian, diagonal-
bandwidth) kernel-density estimate over samples, via regime (iii)
KLD-EM. The proxy is closed-form marginalisable, conditionable, and
samplable; the KDE is none of those things on its own.
from_kde( samples, N = 3L, bandwidth = "silverman", proposal = NULL, is_size = 5000L, max_iter = 100L, tol = 1e-05, ridge_eps = 1e-06, min_ess = 50L, seed = NULL, validation_size = 0L, validation_proposal = NULL, validation_seed = NULL, support_warn = TRUE, canonicalise = TRUE )from_kde( samples, N = 3L, bandwidth = "silverman", proposal = NULL, is_size = 5000L, max_iter = 100L, tol = 1e-05, ridge_eps = 1e-06, min_ess = 50L, seed = NULL, validation_size = 0L, validation_proposal = NULL, validation_seed = NULL, support_warn = TRUE, canonicalise = TRUE )
samples |
An |
N |
Number of mixture components in the proxy. |
bandwidth |
Either |
proposal |
Optional is_proposal. Default is a multivariate-t
centred at |
is_size |
Importance-sample size for fitting. Default |
max_iter |
Maximum EM iterations. Forwarded to |
tol |
Convergence tolerance. Forwarded to |
ridge_eps |
Ridge added to each component covariance at every
M-step. Forwarded to |
min_ess |
Minimum effective sample size below which a warning is
issued. Forwarded to |
seed |
Optional integer seed for the fitting IS draw. |
validation_size |
Held-out IS sample size. Forwarded to
|
validation_proposal |
Optional is_proposal for the held-out
sample. Forwarded to |
validation_seed |
Optional integer seed for the held-out IS draw.
Forwarded to |
support_warn |
Logical. Forwarded to |
canonicalise |
Logical. If |
This is a compression operation: take an n-sample KDE and replace
it with the closest N-component mixture in the Kullback-Leibler sense
(which is much smaller than n for typical use). Bias inherited from
the KDE is reproduced in the proxy; the bandwidth controls the
bias-variance trade-off.
Dimensional scope. The dimensional guard is p <= 5 (recommended),
p <= 10 (allowed with warning), p > 10 (rejected). Regime-(iii)
KLD-EM is driven by importance sampling, whose effective sample size
collapses sharply in high dimensions.
A gmm_fit with regime = "kld" and metadata recording the
KDE inputs (kde_samples_n, bandwidth, bandwidth_method).
Other fitting:
fit_em_samples(),
fit_kld_em(),
fit_moment_match(),
from_objective(),
select_N()
set.seed(1L) x <- rbind( mvnfast::rmvn(120L, mu = c(-2, 0), sigma = diag(2)), mvnfast::rmvn(120L, mu = c( 2, 0), sigma = diag(2)) ) fit <- from_kde(x, N = 2L, is_size = 2000L, max_iter = 40L, seed = 1L) fit ess_summary(fit)set.seed(1L) x <- rbind( mvnfast::rmvn(120L, mu = c(-2, 0), sigma = diag(2)), mvnfast::rmvn(120L, mu = c( 2, 0), sigma = diag(2)) ) fit <- from_kde(x, N = 2L, is_size = 2000L, max_iter = 40L, seed = 1L) fit ess_summary(fit)
Fits a Gaussian-mixture proxy to the Gibbs measure
of a user-supplied objective f over a bounded
box, by cooling a short temperature ladder through regime-(iii)
importance-sampled KLD-EM (fit_kld_em()). As the temperature falls the
mixture mass concentrates on the low regions of f, so the fitted
mixture is a closed-form map over the optima rather than a single
point estimate. Pair it with gmm_modes() to read off the distinct
optima.
from_objective( objective, lower, upper, N = NULL, minimise = TRUE, temperature = NULL, n_steps = 6L, exploration = 0.5, inflate = 1.8, is_size = 10000L, max_iter = 70L, ridge_eps = 1e-04, seed = NULL )from_objective( objective, lower, upper, N = NULL, minimise = TRUE, temperature = NULL, n_steps = 6L, exploration = 0.5, inflate = 1.8, is_size = 10000L, max_iter = 70L, ridge_eps = 1e-04, seed = NULL )
objective |
Function taking a length- |
lower, upper
|
Numeric vectors of equal length |
N |
Number of mixture components. Default |
minimise |
Logical. If |
temperature |
Optional control of the cooling ladder. |
n_steps |
Number of temperatures in the cooling ladder. Default
|
exploration |
Probability mass the importance proposal places on
uniform exploration of the box at each step, in |
inflate |
Factor by which the current mixture covariances are
inflated when used as the exploitation part of the proposal. Default
|
is_size |
Importance-sample size per cooling step. Default |
max_iter |
Maximum EM iterations per cooling step. Default |
ridge_eps |
Ridge added to each component covariance at every
M-step. Forwarded to |
seed |
Optional integer seed for reproducibility. |
The Gibbs measure can be evaluated point-wise but not directly sampled,
which is precisely the setting of regime (iii): minimising
the Kullback-Leibler divergence from a Gaussian mixture to a peaked
target is the rank-weighted Gaussian update at the heart of fit_kld_em().
This function is that fit, driven against a sequence of cooling Gibbs
targets and warm-started from the previous fit at each step. Because a
multimodal f produces a multimodal target, the components spread across
the basins and recover the optima together.
Recovery is most reliable with component headroom – a number of
components N comfortably larger than the number of optima you expect,
so the defensive proposal can keep a component on each basin. Symmetric
landscapes (where several optima are exchangeable) need the most headroom.
Dimensional scope. As with the rest of regime (iii), the importance-
sampling effective sample size falls sharply with dimension; the guard is
p <= 5 (recommended), p <= 10 (allowed with a warning), p > 10
(rejected).
A gmm_fit (the fitted proxy) carrying a from_objective
metadata record with the temperature ladder and box. Pass it to
gmm_modes() to extract the distinct optima.
gmm_modes() to resolve the fitted map into distinct optima.
Other fitting:
fit_em_samples(),
fit_kld_em(),
fit_moment_match(),
from_kde(),
select_N()
## A bimodal 1-D objective with minima at +/- 2. f <- function(v) (v[1]^2 - 4)^2 fit <- from_objective(f, lower = -5, upper = 5, N = 6L, is_size = 2000L, n_steps = 5L, seed = 1L) gmm_modes(fit)$modes## A bimodal 1-D objective with minima at +/- 2. f <- function(v) (v[1]^2 - 4)^2 fit <- from_objective(f, lower = -5, upper = 5, N = 6L, is_size = 2000L, n_steps = 5L, seed = 1L) gmm_modes(fit)$modes
A broom-style glance() method: a one-row summary of a gmm_fit with
the regime, the component count and dimension, convergence, iteration
count, and the regime's headline fit statistics. Available as
generics::glance(fit) when the generics package is installed.
x |
A gmm_fit. |
... |
Ignored, for generic compatibility. |
A one-row data frame.
Other classes:
autoplot.gmm_fit,
gmm(),
gmm_counterfactual_law(),
gmm_dim(),
gmm_fit(),
gmm_n_components(),
gmm_target(),
gmm_weights(),
is_proposal(),
tidy.gmm
fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1000L, max_iter = 10L, seed = 1L) generics::glance(fit)fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1000L, max_iter = 10L, seed = 1L) generics::glance(fit)
Lightweight S7 class representing an N-component multivariate Gaussian
mixture on . Use gmm() to construct, dgmm() / rgmm()
to evaluate or sample, and gmm_marginalise() / gmm_conditionalise()
for closed-form operations.
gmm( weights = numeric(0), means = list(), covariances = list(), name = "gmm", metadata = list() )gmm( weights = numeric(0), means = list(), covariances = list(), name = "gmm", metadata = list() )
weights |
Numeric vector of length |
means |
List of length |
covariances |
List of length |
name |
Optional human-readable name. |
metadata |
Optional list of arbitrary metadata (regime tags, diagnostic snapshots, etc.). |
An S7 object inheriting from gmm.
Other classes:
autoplot.gmm_fit,
glance.gmm_fit,
gmm_counterfactual_law(),
gmm_dim(),
gmm_fit(),
gmm_n_components(),
gmm_target(),
gmm_weights(),
is_proposal(),
tidy.gmm
g <- gmm( weights = c(0.4, 0.6), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2)) ) gg <- gmm( weights = c(0.4, 0.6), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2)) ) g
Returns the (closed-form) distribution of
when is a Gaussian mixture and is independent additive Gaussian noise.
gmm_affine(g, A, b = 0, noise_cov = NULL, ridge_eps = 1e-06)gmm_affine(g, A, b = 0, noise_cov = NULL, ridge_eps = 1e-06)
g |
|
A |
An |
b |
Numeric scalar or length- |
noise_cov |
|
ridge_eps |
Tiny ridge added to the output covariances for
numerical hygiene. Set to |
For each component k, the pushed-forward parameters are
and the mixture weights are unchanged. This is the finite-mixture analogue of a Kalman-style predict step.
The channel is required to be affine in x and the noise is
required to be Gaussian. Non-linear channels are not closed form and
are not silently approximated: push samples through the map instead
(rgmm() then the transform) and refit with fit_em_samples() when a
mixture of the image is needed.
A gmm in R^m with the same number of components and the
same weights as g.
Other operators:
gmm_aggregate(),
gmm_convolve(),
gmm_counterfactual(),
gmm_filter(),
gmm_intervene(),
gmm_missing(),
gmm_mix(),
gmm_observe(),
gmm_product(),
gmm_reduce()
g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) A <- matrix(c(1, 0, 0, 1, 1, -1), nrow = 3L, byrow = TRUE) gmm_affine(g, A, b = c(0, 0, 0), noise_cov = 0.01 * diag(3))g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) A <- matrix(c(1, 0, 0, 1, 1, -1), nrow = 3L, byrow = TRUE) gmm_affine(g, A, b = c(0, 0, 0), noise_cov = 0.01 * diag(3))
A named alias for gmm_affine() when A is a (row-wise) aggregation
matrix — e.g. a block-sum, block-average, or unequal-weight aggregation
used in downscaling pipelines. The mathematics is identical to
gmm_affine(); the alias gives the public API a clearer hook for
aggregation-specific diagnostics in later releases.
gmm_aggregate(g, A, noise_cov = NULL, ridge_eps = 1e-06)gmm_aggregate(g, A, noise_cov = NULL, ridge_eps = 1e-06)
g |
|
A |
An |
noise_cov |
Optional |
ridge_eps |
Tiny ridge added to the output covariances for numerical hygiene. |
A gmm in R^m.
Other operators:
gmm_affine(),
gmm_convolve(),
gmm_counterfactual(),
gmm_filter(),
gmm_intervene(),
gmm_missing(),
gmm_mix(),
gmm_observe(),
gmm_product(),
gmm_reduce()
g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0, 1), c(1, 0, -1)), covariances = list(diag(3), diag(3))) # Sum coordinates 1 and 2 into a single aggregate; pass coord 3 through. A <- matrix(c(1, 1, 0, 0, 0, 1), nrow = 2L, byrow = TRUE) gmm_aggregate(g, A)g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0, 1), c(1, 0, -1)), covariances = list(diag(3), diag(3))) # Sum coordinates 1 and 2 into a single aggregate; pass coord 3 through. A <- matrix(c(1, 1, 0, 0, 0, 1), nrow = 2L, byrow = TRUE) gmm_aggregate(g, A)
Tracks the number of distinct mixture centroids as a function of temperature
under mass-constrained deterministic annealing (Rose, Gurewitz and Fox 1990),
a physics-derived alternative to information-criterion model selection. The
system starts at a high temperature where all k_max centroids collapse to
the data centroid (a single effective component) and is cooled along a
geometric schedule; at each critical temperature a centroid bifurcates, so the
number of distinct centroids grows in steps. The temperatures at which it
grows are the phase transitions, and the count occupying the widest
temperature range is the discovered component number.
gmm_anneal_path( x, k_max = 8L, sigma = NULL, t_high = NULL, t_low = NULL, n_steps = 80L, n_inner = 30L, w = NULL, perturb = 0.02, merge_tol = 0.1, ridge_eps = 1e-06, seed = 1L )gmm_anneal_path( x, k_max = 8L, sigma = NULL, t_high = NULL, t_low = NULL, n_steps = 80L, n_inner = 30L, w = NULL, perturb = 0.02, merge_tol = 0.1, ridge_eps = 1e-06, seed = 1L )
x |
A numeric |
k_max |
Maximum number of centroids tracked (the discovered count is at
most |
sigma |
Reference scale: the shared covariance is |
t_high, t_low
|
Top and bottom of the temperature schedule. When |
n_steps |
Number of temperatures on the geometric schedule. |
n_inner |
Fixed-point iterations run at each temperature. |
w |
Optional length- |
perturb |
Symmetry-breaking perturbation, as a fraction of the data scale, applied to the centroids at each temperature. |
merge_tol |
Two centroids count as distinct when their distance exceeds
|
ridge_eps |
Ridge added to the reference covariance for stability. |
seed |
Optional integer seed for the perturbations (the result is deterministic given a seed). |
The first bifurcation has a closed-form critical temperature
, where is the (weighted)
data covariance and the shared reference covariance.
This value is returned as t_critical_analytic and serves as an independent
analytic check on the empirically detected first transition. Subsequent
transitions have no comparably simple closed form, and the count is a
diagnostic rather than a guarantee.
Annealing fixes the component covariance to the reference so the
temperature is the only scale; this is the clean isotropic regime in which the
critical temperature is exact. For robust fitting under free covariances,
use anneal = TRUE on fit_em_samples() or fit_kld_em() instead.
A list with elements path (a data frame of temperature,
n_effective and free_energy), critical_temperatures (the temperatures
at which the count increased), first_critical_temperature (the first such,
or NA if none was detected), t_critical_analytic
(), k_selected (the widest-plateau
component count), lambda_max and sigma.
Rose, K., Gurewitz, E. and Fox, G. C. (1990) Statistical mechanics and phase transitions in clustering. Physical Review Letters 65(8), 945–948. doi:10.1103/PhysRevLett.65.945
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
set.seed(1) x <- rbind( matrix(stats::rnorm(120, mean = -4), ncol = 2), matrix(stats::rnorm(120, mean = 4), ncol = 2) ) path <- gmm_anneal_path(x, k_max = 4L, n_steps = 40L) path$k_selected path$first_critical_temperatureset.seed(1) x <- rbind( matrix(stats::rnorm(120, mean = -4), ncol = 2), matrix(stats::rnorm(120, mean = 4), ncol = 2) ) path <- gmm_anneal_path(x, k_max = 4L, n_steps = 40L) path$k_selected path$first_critical_temperature
Returns a new gmm (or gmm_fit) with the components permuted into a
canonical order: weight descending, then ||mu|| descending as a
tiebreaker. The mixture distribution is unchanged — only the bookkeeping
order is — but the canonical ordering removes the EM label-switching
nuisance from snapshot tests, cross-run comparisons, and printed
summaries.
gmm_canonicalise(g)gmm_canonicalise(g)
g |
Applied automatically by the regime-specific fitters
(fit_moment_match(), fit_em_samples(), fit_kld_em()) and by the
top-level dispatcher fit_proxymix() when canonicalise = TRUE
(the default).
A gmm (or gmm_fit) of the same subclass as g, with the
components permuted into canonical order.
Other ops:
dgmm(),
gmm_conditionalise(),
gmm_divergence(),
gmm_kld(),
gmm_marginalise(),
gmm_mean(),
gmm_modes(),
pgmm(),
rgmm()
g <- gmm(weights = c(0.1, 0.6, 0.3), means = list(c(0, 0), c(3, 0), c(-1, 1)), covariances = list(diag(2), diag(2), diag(2))) gmm_canonicalise(g)g <- gmm(weights = c(0.1, 0.6, 0.3), means = list(c(0, 0), c(3, 0), c(-1, 1)), covariances = list(diag(2), diag(2), diag(2))) gmm_canonicalise(g)
Returns the one identified summary of a gmm_counterfactual_law – its mean.
gmm_cf_mean(x)gmm_cf_mean(x)
x |
A |
Numeric scalar.
Other decision:
fit_uplift(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
g <- gmm(weights = 1, means = list(c(0, 0, 0)), covariances = list(diag(3))) cf <- gmm_counterfactual(g, evidence = c(1, 0, 0.2), do = c(NA, 1, NA), query = 1L) gmm_cf_mean(cf)g <- gmm(weights = 1, means = list(c(0, 0, 0)), covariances = list(diag(3))) cf <- gmm_counterfactual(g, evidence = c(1, 0, 0.2), do = c(NA, 1, NA), query = 1L) gmm_cf_mean(cf)
Like gmm_cf_variance(), a per-unit counterfactual tail probability
is not identified – it is a functional of
the unidentified counterfactual law, not of its identified mean. This
accessor refuses rather than mislead.
gmm_cf_tail_prob(x, threshold)gmm_cf_tail_prob(x, threshold)
x |
|
threshold |
Numeric scalar |
Never returns; always raises a proxymix_not_identified error.
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
g <- gmm(weights = 1, means = list(c(0, 0, 0)), covariances = list(diag(3))) cf <- gmm_counterfactual(g, evidence = c(1, 0, 0.2), do = c(NA, 1, NA), query = 1L) try(gmm_cf_tail_prob(cf, threshold = 2))g <- gmm(weights = 1, means = list(c(0, 0, 0)), covariances = list(diag(3))) cf <- gmm_counterfactual(g, evidence = c(1, 0, 0.2), do = c(NA, 1, NA), query = 1L) try(gmm_cf_tail_prob(cf, threshold = 2))
The per-unit counterfactual variance is not identified from the joint density: it depends on the cross-world coupling of the structural residuals under the factual and counterfactual treatments, which no goodness-of-fit can certify. This accessor therefore raises an error rather than return the (misleading) spread of the abduction atoms.
gmm_cf_variance(x)gmm_cf_variance(x)
x |
Never returns; always raises a proxymix_not_identified error.
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
g <- gmm(weights = 1, means = list(c(0, 0, 0)), covariances = list(diag(3))) cf <- gmm_counterfactual(g, evidence = c(1, 0, 0.2), do = c(NA, 1, NA), query = 1L) try(gmm_cf_variance(cf))g <- gmm(weights = 1, means = list(c(0, 0, 0)), covariances = list(diag(3))) cf <- gmm_counterfactual(g, evidence = c(1, 0, 0.2), do = c(NA, 1, NA), query = 1L) try(gmm_cf_variance(cf))
gmm_imputation
Extract completed datasets from a gmm_imputation
gmm_complete(object, which = 1L)gmm_complete(object, which = 1L)
object |
|
which |
Either an integer vector of imputation indices, or |
When which selects one completion, a single completed dataset
(matrix, or data frame if the input was one); otherwise a list of them.
Other imputation:
as_mids(),
gmm_imputation(),
gmm_impute(),
mechanism,
proxy_fmi(),
proxy_mnar_sensitivity(),
proxy_pool()
Returns the differential entropy of the conditional mixture obtained from gmm_conditionalise() – the predictive uncertainty of
the target coordinates given the conditioned ones. The order-2 Renyi entropy
is closed-form; order = "shannon" falls back to Monte Carlo. Multiple
conditioning configurations are evaluated row-by-row.
gmm_conditional_entropy( g, given, order = c("renyi2", "shannon"), n_mc = 5000L, seed = NULL )gmm_conditional_entropy( g, given, order = c("renyi2", "shannon"), n_mc = 5000L, seed = NULL )
g |
|
given |
Either a numeric vector with one entry per coordinate, or a
matrix whose rows are such vectors. |
order |
|
n_mc, seed
|
Passed to |
A numeric scalar for a single configuration, or a numeric vector
with one entropy per row of given.
gmm_entropy(), gmm_conditionalise()
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
## Joint over (Y, X); predictive entropy of Y at several X values. s <- matrix(c(2, 0.8, 0.8, 1), 2, 2) g <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(s)) gmm_conditional_entropy(g, given = rbind(c(NA, 0), c(NA, 1)))## Joint over (Y, X); predictive entropy of Y at several X values. s <- matrix(c(2, 0.8, 0.8, 1), 2, 2) g <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(s)) gmm_conditional_entropy(g, given = rbind(c(NA, 0), c(NA, 1)))
Computes the conditional distribution of a Gaussian mixture given fixed
values of a subset of coordinates, by the Schur-complement formula
applied component-wise and re-weighted by the marginal evidence
of each component.
gmm_conditionalise(g, given)gmm_conditionalise(g, given)
g |
|
given |
A length- |
A gmm object in dimension equal to the number of free coordinates.
Other ops:
dgmm(),
gmm_canonicalise(),
gmm_divergence(),
gmm_kld(),
gmm_marginalise(),
gmm_mean(),
gmm_modes(),
pgmm(),
rgmm()
g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) gmm_conditionalise(g, given = c(NA, 0.5))g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) gmm_conditionalise(g, given = c(NA, 0.5))
The exact distribution of for independent
and : a Gaussian mixture with components,
gmm_convolve(g1, g2)gmm_convolve(g1, g2)
g1, g2
|
For the affine special case with a constant c, or
with Gaussian , use gmm_affine();
the convolution operator is the general mixture-plus-mixture case that
gmm_affine() cannot express.
A gmm with K1 * K2 components.
Other operators:
gmm_affine(),
gmm_aggregate(),
gmm_counterfactual(),
gmm_filter(),
gmm_intervene(),
gmm_missing(),
gmm_mix(),
gmm_observe(),
gmm_product(),
gmm_reduce()
g1 <- gmm(weights = c(0.5, 0.5), means = list(-1, 1), covariances = list(matrix(0.5), matrix(0.5))) g2 <- gmm(weights = 1, means = list(2), covariances = list(matrix(1))) gmm_convolve(g1, g2)g1 <- gmm(weights = c(0.5, 0.5), means = list(-1, 1), covariances = list(matrix(0.5), matrix(0.5))) g2 <- gmm(weights = 1, means = list(2), covariances = list(matrix(1))) gmm_convolve(g1, g2)
Computes the per-unit counterfactual of a query coordinate (the outcome)
for an observed unit, under a do() intervention – Pearl's third rung on
the latent-class structural causal model read off a fitted Gaussian
mixture.
gmm_counterfactual(g, evidence, do, query, ridge_eps = 1e-06)gmm_counterfactual(g, evidence, do, query, ridge_eps = 1e-06)
g |
|
evidence |
A length- |
do |
A length- |
query |
A single integer coordinate index in |
ridge_eps |
Tiny ridge added to the conditioning covariances for numerical hygiene. |
The three steps are closed form. Abduction recovers the regime posterior
of the observed unit and, within each
component, its structural residual. Action sets the do coordinates.
Prediction re-evaluates the query coordinate. For a binary treatment the
result is a discrete law on K atoms,
where is component k's within-class treatment slope. Only
the mean of this law is identified; its spread reflects regime
uncertainty, not the (unidentified) cross-world coupling, so the variance
and tail accessors refuse to answer (see gmm_cf_variance()).
A gmm_counterfactual_law object carrying the K atoms, their
abduction weights, and the identified counterfactual mean.
gmm_intervene(), gmm_cf_variance(), proxy_retrospective_uplift()
Other operators:
gmm_affine(),
gmm_aggregate(),
gmm_convolve(),
gmm_filter(),
gmm_intervene(),
gmm_missing(),
gmm_mix(),
gmm_observe(),
gmm_product(),
gmm_reduce()
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
## Observed unit (y = 1.2, t = 0, x = 0.5); imagine t = 1. g <- gmm(weights = c(0.6, 0.4), means = list(c(0, 0, 0), c(2, 1, 1)), covariances = list(diag(3), diag(3))) cf <- gmm_counterfactual(g, evidence = c(1.2, 0, 0.5), do = c(NA, 1, NA), query = 1L) cf@mean## Observed unit (y = 1.2, t = 0, x = 0.5); imagine t = 1. g <- gmm(weights = c(0.6, 0.4), means = list(c(0, 0, 0), c(2, 1, 1)), covariances = list(diag(3), diag(3))) cf <- gmm_counterfactual(g, evidence = c(1.2, 0, 0.5), do = c(NA, 1, NA), query = 1L) cf@mean
The return type of gmm_counterfactual(): a discrete law on K atoms (the
per-component counterfactual outcomes) with abduction weights, plus the one
identified summary – the counterfactual mean. The atom spread is regime
(epistemic) uncertainty about which structural component generated the unit;
it is not the counterfactual outcome's dispersion, which is unidentified.
Accordingly gmm_cf_variance() and gmm_cf_tail_prob() refuse to answer.
gmm_counterfactual_law( atoms = numeric(0), weights = numeric(0), mean = numeric(0), query = integer(0), evidence = numeric(0), do = numeric(0), name = "gmm_counterfactual_law", metadata = list() )gmm_counterfactual_law( atoms = numeric(0), weights = numeric(0), mean = numeric(0), query = integer(0), evidence = numeric(0), do = numeric(0), name = "gmm_counterfactual_law", metadata = list() )
atoms |
Numeric vector of length |
weights |
Numeric vector of length |
mean |
Numeric scalar – the identified counterfactual mean. |
query |
Integer scalar – the queried coordinate index. |
evidence |
Numeric vector – the observed unit. |
do |
Numeric vector – the intervention. |
name |
Human-readable name. |
metadata |
Optional list of descriptors. |
An S7 object of class gmm_counterfactual_law.
Other classes:
autoplot.gmm_fit,
glance.gmm_fit,
gmm(),
gmm_dim(),
gmm_fit(),
gmm_n_components(),
gmm_target(),
gmm_weights(),
is_proposal(),
tidy.gmm
Convenience accessor returning the ambient dimension .
gmm_dim(x)gmm_dim(x)
x |
Integer scalar.
Other classes:
autoplot.gmm_fit,
glance.gmm_fit,
gmm(),
gmm_counterfactual_law(),
gmm_fit(),
gmm_n_components(),
gmm_target(),
gmm_weights(),
is_proposal(),
tidy.gmm
g <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(diag(2))) gmm_dim(g)g <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(diag(2))) gmm_dim(g)
Computes a divergence between two Gaussian mixtures of the same ambient dimension. The Cauchy-Schwarz divergence
with , is closed-form, symmetric,
non-negative, and zero exactly when . The "kl" option
delegates to gmm_kld(), a Monte-Carlo estimate of the asymmetric
Kullback-Leibler divergence .
gmm_divergence(p, q, type = c("cs", "kl"), n_mc = 5000L)gmm_divergence(p, q, type = c("cs", "kl"), n_mc = 5000L)
p, q
|
|
type |
|
n_mc |
Number of Monte Carlo samples used when |
For type = "cs", a non-negative numeric scalar. For type = "kl",
the list returned by gmm_kld().
Other ops:
dgmm(),
gmm_canonicalise(),
gmm_conditionalise(),
gmm_kld(),
gmm_marginalise(),
gmm_mean(),
gmm_modes(),
pgmm(),
rgmm()
p <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) q <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(diag(2) * 2)) gmm_divergence(p, q) gmm_divergence(p, p)p <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) q <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(diag(2) * 2)) gmm_divergence(p, q) gmm_divergence(p, p)
Computes the differential entropy of a Gaussian mixture. The quadratic
(order-2) Renyi entropy is available in
closed form, because is a finite sum of Gaussian-density
evaluations. Shannon entropy has no closed form for a mixture (the integrand
carries the logarithm of a sum) and is estimated by Monte Carlo, reported
with its standard error and an analytic upper bound that brackets it from
above.
gmm_entropy(g, order = c("renyi2", "shannon"), n_mc = 5000L, seed = NULL)gmm_entropy(g, order = c("renyi2", "shannon"), n_mc = 5000L, seed = NULL)
g |
|
order |
|
n_mc |
Number of Monte Carlo samples for |
seed |
Optional integer seed for the Monte Carlo draw. |
For order = "renyi2", a numeric scalar. For order = "shannon", a
list with components mc (the estimate), mc_se (its standard error),
upper_bound (the analytic upper bound), and n_mc.
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
g <- gmm(weights = c(0.5, 0.5), means = list(c(-2, 0), c(2, 0)), covariances = list(diag(2), diag(2))) gmm_entropy(g) gmm_entropy(g, order = "shannon", n_mc = 2000L, seed = 1L)g <- gmm(weights = c(0.5, 0.5), means = list(c(-2, 0), c(2, 0)), covariances = list(diag(2), diag(2))) gmm_entropy(g) gmm_entropy(g, order = "shannon", n_mc = 2000L, seed = 1L)
Tests whether the last m observations of a series are consistent with a
linear-Gaussian state-space model fitted on the rest, in the regime where m
is small (even m = 1) and smaller than the parameter count – where ordinary
structural-break tests (Chow, sup-Wald) are undefined because the post-break
parameters cannot be estimated. The statistic is the sum of the last m
squared standardised one-step innovations from the filter; a break inflates it.
gmm_eos_test( prior, dynamics, measurement, y, m = 1L, method = c("chisq", "andrews"), alpha = 0.05 )gmm_eos_test( prior, dynamics, measurement, y, m = 1L, method = c("chisq", "andrews"), alpha = 0.05 )
prior |
A single-component gmm giving the state prior (the test is defined for a fitted linear-Gaussian model; multi-component priors are not yet supported). |
dynamics |
A list with |
measurement |
A list with |
y |
A numeric vector or an |
m |
Integer; the number of end-of-sample observations to test, |
method |
Either |
alpha |
The nominal level used to set |
Two calibrations are offered. method = "chisq" refers the statistic to a
chi-square distribution on m * ncol(y) degrees of freedom, which is exact
when the standardised innovations are Gaussian. method = "andrews" is the
distribution-free Andrews (2003) subsampling P-test: the statistic's rank among
the in-sample overlapping m-blocks of the same innovations gives the p-value,
so it stays calibrated when the innovations are non-Gaussian (heavy-tailed
observation noise, say). The model is supplied exactly as for gmm_filter().
Two finite-sample cautions. The chi-square calibration is exact when the
model is given; with parameters estimated on a short series it over-rejects
(size 0.068 at n = 30 against a nominal 0.05 in the validation study,
settling to 0.044 by n = 120), so prefer method = "andrews" when the
model is estimated on little data. The subsampling p-value has a floor of
1 / (n - 2m + 2), so it can reject at level 0.05 only when n > 2m + 18.
An object of class gmm_eos_test: a list with the statistic, the
p_value, the logical reject, the method, m, alpha, and the
in-sample block statistics used for the subsampling calibration.
Andrews, D. W. K. (2003). End-of-Sample Instability Tests. Econometrica, 71(6), 1661–1694.
prior <- gmm(weights = 1, means = list(0), covariances = list(matrix(10))) dyn <- list(A = matrix(1), Q = matrix(0.04)) meas <- list(C = matrix(1), R = matrix(1)) set.seed(1) y <- c(rnorm(119), 6) # a stable series with a jump at the end gmm_eos_test(prior, dyn, meas, y, m = 1L, method = "andrews")prior <- gmm(weights = 1, means = list(0), covariances = list(matrix(10))) dyn <- list(A = matrix(1), Q = matrix(0.04)) meas <- list(C = matrix(1), R = matrix(1)) set.seed(1) y <- c(rnorm(119), 6) # a stable series with a jump at the end gmm_eos_test(prior, dyn, meas, y, m = 1L, method = "andrews")
Importance-sampling estimate of for the fit's
target , using the fitted mixture as the proposal:
computed in the log domain. For a Bayesian posterior handed over as
likelihood x prior, is the log marginal likelihood, so a
fitted proxy doubles as a model-comparison device.
gmm_evidence(fit, n = 4000L, seed = NULL)gmm_evidence(fit, n = 4000L, seed = NULL)
fit |
A gmm_fit whose target carries a |
n |
Number of evidence draws from the fitted proxy. |
seed |
Optional integer seed for the evidence draw. |
The estimator is exact in expectation for any proposal that dominates
, and its Monte Carlo error is driven by how well
matches – which is precisely what the fit optimised. The
variance is finite only when has tails at least as heavy
as ; a right-tail diagnostic is returned (the effective sample
size and the share of the estimate carried by the largest ten percent
of weights, which sits near 0.10 for a well-matched proxy), and a
classed warning (proxymix_heavy_tail) is raised when it indicates an
untrustworthy tail. Results also report the delta-method standard error
of .
When the target declares itself normalised (normalised = TRUE), the
true value is and the function still estimates it –
a useful end-to-end diagnostic of the fit.
A list of class proxymix_evidence with elements log_z,
se_log_z, n, ess, max_weight_share, top_decile_share, and
flagged (the heavy-tail indicator).
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
## An unnormalised target with a known constant: log f = log N(., 0, I) + 3. tgt <- gmm_target( n_dim = 2L, log_density = function(x) { if (is.null(dim(x))) x <- matrix(x, ncol = 2L) -0.5 * rowSums(x^2) - log(2 * pi) + 3 }, normalised = FALSE, name = "shifted_gaussian" ) fit <- fit_kld_em(tgt, N = 1L, is_size = 2000L, max_iter = 40L, seed = 1L) ev <- gmm_evidence(fit, n = 2000L, seed = 2L) ev$log_z # close to 3## An unnormalised target with a known constant: log f = log N(., 0, I) + 3. tgt <- gmm_target( n_dim = 2L, log_density = function(x) { if (is.null(dim(x))) x <- matrix(x, ncol = 2L) -0.5 * rowSums(x^2) - log(2 * pi) + 3 }, normalised = FALSE, name = "shifted_gaussian" ) fit <- fit_kld_em(tgt, N = 1L, is_size = 2000L, max_iter = 40L, seed = 1L) ev <- gmm_evidence(fit, n = 2000L, seed = 2L) ev$log_z # close to 3
Runs a Gaussian-sum filter over a series of n observations by alternating
the predict operator gmm_affine(), the update operator gmm_observe() and
an optional reduction gmm_reduce(). At one component this is the classical
Kalman filter; at several components, with Gaussian-mixture process or
measurement noise, it is the Gaussian-sum filter of Alspach and Sorenson
(1972). The filter is a pure composition of the existing closed-form
operators; nothing here leaves the affine-Gaussian world.
gmm_filter( prior, dynamics, measurement, y, k_max = NULL, reduce = c("merge", "anneal"), ridge_eps = 1e-08 )gmm_filter( prior, dynamics, measurement, y, k_max = NULL, reduce = c("merge", "anneal"), ridge_eps = 1e-08 )
prior |
|
dynamics |
A list |
measurement |
A list |
y |
The observations: an |
k_max |
Optional component cap. |
reduce |
The reduction method passed to |
ridge_eps |
Tiny ridge passed to |
At step the belief is propagated through the linear-Gaussian dynamics
, then conditioned on the observation
, then (if k_max is set) reduced back to at most
k_max components. With Gaussian noise the component count is constant and
the recursion is the Kalman filter. Non-Gaussian noise is supplied as a
Gaussian sum – a gmm in place of the covariance matrix Q or R. Each
such mixture multiplies the component count by its own component count every
step, so a long horizon is only runnable with reduction enabled. Reduction is
moment-preserving (see gmm_reduce()), so the filtered mean and covariance
are unaffected to the moment-matching order while the count stays bounded.
A list with elements
filtereda length-n list of the filtered gmm beliefs, one
per step (after predict, update and any reduction).
meanan n-by-p matrix of the filtered mixture means.
cova length-n list of the p-by-p filtered mixture
covariances.
summarya data frame with one row per step: the step index, the
per-coordinate filtered mean (mean_1, ...) and standard deviation
(sd_1, ...), the component count n_components, and the step log
marginal evidence log_evidence (whose sum over steps is the log
likelihood of the series).
Alspach, D. L. and Sorenson, H. W. (1972) Nonlinear Bayesian estimation using Gaussian sum approximations. IEEE Transactions on Automatic Control 17(4), 439–448. doi:10.1109/TAC.1972.1100034
Other operators:
gmm_affine(),
gmm_aggregate(),
gmm_convolve(),
gmm_counterfactual(),
gmm_intervene(),
gmm_missing(),
gmm_mix(),
gmm_observe(),
gmm_product(),
gmm_reduce()
## A one-dimensional local-level filter (random walk observed in noise). prior <- gmm(weights = 1, means = list(0), covariances = list(matrix(1))) truth <- cumsum(stats::rnorm(20, sd = 0.3)) y <- truth + stats::rnorm(20, sd = 0.5) out <- gmm_filter( prior, dynamics = list(A = matrix(1), Q = matrix(0.09)), measurement = list(C = matrix(1), R = matrix(0.25)), y = y ) head(out$summary) ## Heavy-tailed process noise as a two-component Gaussian sum, capped at ## four components per step. q_noise <- gmm(weights = c(0.9, 0.1), means = list(0, 0), covariances = list(matrix(0.05), matrix(1))) out2 <- gmm_filter( prior, dynamics = list(A = matrix(1), Q = q_noise), measurement = list(C = matrix(1), R = matrix(0.25)), y = y, k_max = 4L ) max(out2$summary$n_components)## A one-dimensional local-level filter (random walk observed in noise). prior <- gmm(weights = 1, means = list(0), covariances = list(matrix(1))) truth <- cumsum(stats::rnorm(20, sd = 0.3)) y <- truth + stats::rnorm(20, sd = 0.5) out <- gmm_filter( prior, dynamics = list(A = matrix(1), Q = matrix(0.09)), measurement = list(C = matrix(1), R = matrix(0.25)), y = y ) head(out$summary) ## Heavy-tailed process noise as a two-component Gaussian sum, capped at ## four components per step. q_noise <- gmm(weights = c(0.9, 0.1), means = list(0, 0), covariances = list(matrix(0.05), matrix(1))) out2 <- gmm_filter( prior, dynamics = list(A = matrix(1), Q = q_noise), measurement = list(C = matrix(1), R = matrix(0.25)), y = y, k_max = 4L ) max(out2$summary$n_components)
A gmm_fit is the result of fit_proxymix() (or one of the regime-specific
fitters). It inherits the mixture parameters of gmm and adds a record of
the target it was fitted to, the regime used, and the iteration
diagnostics.
gmm_fit( weights = numeric(0), means = list(), covariances = list(), name = "gmm", metadata = list(), target = NULL, regime = NA_character_, diagnostics = list(), converged = NA, iterations = NA_integer_, call = NULL )gmm_fit( weights = numeric(0), means = list(), covariances = list(), name = "gmm", metadata = list(), target = NULL, regime = NA_character_, diagnostics = list(), converged = NA, iterations = NA_integer_, call = NULL )
weights, means, covariances, name, metadata
|
See gmm. |
target |
The gmm_target the mixture was fitted to. |
regime |
One of |
diagnostics |
A list of regime-specific diagnostics
(see |
converged |
Logical scalar. |
iterations |
Integer scalar. |
call |
The matched call. |
An S7 object inheriting from gmm_fit (and gmm).
Other classes:
autoplot.gmm_fit,
glance.gmm_fit,
gmm(),
gmm_counterfactual_law(),
gmm_dim(),
gmm_n_components(),
gmm_target(),
gmm_weights(),
is_proposal(),
tidy.gmm
samples <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(samples) fit <- fit_proxymix(tgt, N = 2L, regime = "sample", max_iter = 25L) inherits(fit, "proxymix::gmm_fit")samples <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(samples) fit <- fit_proxymix(tgt, N = 2L, regime = "sample", max_iter = 25L) inherits(fit, "proxymix::gmm_fit")
Quantifies the sampling variability of the fitted mixture itself by a
Bayesian (weighted) bootstrap: each replicate re-weights the fit's own
observations with Dirichlet(1, ..., 1) weights and refits by a
warm-started weighted EM. In regime "kld" the observations are the
fit's cached importance draws with their self-normalised weights, so a
replicate costs zero new target evaluations; in regimes "sample"
and "moment" the observations are the target's samples. Summaries of
any functional of the proxy are then read off the ensemble with
proxy_functional_ci() – functional-space intervals sidestep the
label-switching that makes parameter-space intervals incoherent.
gmm_fit_ensemble(fit, B = 200L, max_iter = 25L, tol = 1e-05, seed = NULL)gmm_fit_ensemble(fit, B = 200L, max_iter = 25L, tol = 1e-05, seed = NULL)
fit |
A gmm_fit whose fitting inputs are recoverable (a
regime- |
B |
Number of bootstrap replicates. |
max_iter, tol
|
Convergence controls for the per-replicate warm-started weighted EM. |
seed |
Optional integer seed for the replicate weights. |
A list of class gmm_ensemble: fit (the base fit),
members (a length-B list of gmm), B, and regime.
Rubin, D. B. (1981) The Bayesian bootstrap. The Annals of Statistics 9(1), 130–134.
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1500L, max_iter = 20L, seed = 1L) ens <- gmm_fit_ensemble(fit, B = 30L, seed = 2L) proxy_functional_ci(ens, gmm_mean)fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1500L, max_iter = 20L, seed = 1L) ens <- gmm_fit_ensemble(fit, B = 30L, seed = 2L) proxy_functional_ci(ens, gmm_mean)
Returns the fit-quality certificate: a small list recording the fitting
regime, convergence, degeneracy, the effective-sample-size profile of
the importance weights, and (when a validation split was drawn) the
held-out validation gap. The certificate is stamped into the object's
metadata at fit time and carried unchanged through every closed-form
operator, so it can be read off a marginal, a conditional, a filtered
belief, or any other derived mixture – alongside the provenance
vector recording the chain of operations that produced it.
gmm_fit_quality(g)gmm_fit_quality(g)
g |
Downstream verbs read the same certificate and raise a one-shot
advisory (class proxymix_low_quality) when the source fit is flagged.
A list with elements regime, converged, degenerate,
ess, ess_relative, min_component_ess, max_weight,
support_fraction, kld_final, and validation_gap (fields not
applicable to the regime are NA), or NULL for a mixture that was
never fitted (e.g. built directly with gmm()).
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1500L, max_iter = 15L, seed = 1L) gmm_fit_quality(fit) ## The certificate survives the operator calculus. gmm_fit_quality(gmm_marginalise(fit, keep = 1L))fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1500L, max_iter = 15L, seed = 1L) gmm_fit_quality(fit) ## The certificate survives the operator calculus. gmm_fit_quality(gmm_marginalise(fit, keep = 1L))
The object returned by gmm_impute(). It carries the m completed data
matrices, the bootstrap-fitted mixtures behind them (used by the analytic
pooling in proxy_pool()), the mixture fitted to the full data, and a
record of the missingness. Pass it to gmm_complete() to extract the
completed datasets and to proxy_pool() / proxy_fmi() for inference.
gmm_imputation( data = NULL, completions = list(), fits = list(), point_fit = NULL, n_components = integer(0), m = integer(0), mechanism = "mar", observed = NULL, var_names = character(0), is_data_frame = FALSE, diagnostics = list(), call = NULL )gmm_imputation( data = NULL, completions = list(), fits = list(), point_fit = NULL, n_components = integer(0), m = integer(0), mechanism = "mar", observed = NULL, var_names = character(0), is_data_frame = FALSE, diagnostics = list(), call = NULL )
data |
The numeric data matrix supplied to |
completions |
List of |
fits |
List of |
point_fit |
The gmm fitted to the full data. |
n_components |
Integer number of mixture components. |
m |
Integer number of completions. |
mechanism |
Missingness mechanism (currently |
observed |
Logical matrix marking the observed entries. |
var_names |
Character vector of column names. |
is_data_frame |
Logical; whether the input was a data frame. |
diagnostics |
List of fit diagnostics (per-column missing rates, convergence, iterations). |
call |
The matched call. |
An S7 object of class gmm_imputation.
Other imputation:
as_mids(),
gmm_complete(),
gmm_impute(),
mechanism,
proxy_fmi(),
proxy_mnar_sensitivity(),
proxy_pool()
Fits a Gaussian mixture to a numeric dataset that contains missing values
and draws m completed datasets from the mixture conditional
. Because the
mixture can be multimodal and heteroscedastic, the imputations follow the
shape of the joint distribution rather than a single Gaussian, which keeps
downstream inference valid on data that a single-Gaussian or
linear-Gaussian imputer mis-specifies.
gmm_impute( data, N = NULL, m = 20L, mechanism = mar(), seed = NULL, max_iter = 100L, tol = 1e-06, ridge_eps = 1e-06 )gmm_impute( data, N = NULL, m = 20L, mechanism = mar(), seed = NULL, max_iter = 100L, tol = 1e-06, ridge_eps = 1e-06 )
data |
A numeric matrix or data frame with |
N |
Number of mixture components. |
m |
Number of completed datasets to draw. Default |
mechanism |
A missingness mechanism: |
seed |
Optional integer seed. When supplied the result is reproducible and the ambient random-number state is restored on exit. |
max_iter |
Maximum EM iterations per fit. Default |
tol |
Relative log-likelihood tolerance for EM convergence. Default
|
ridge_eps |
Ridge added to each component covariance at every M-step.
Default |
Imputation is conditioning. For a row with observed coordinates the
missing coordinates follow the closed-form mixture conditional (the same
Schur-complement algebra as gmm_conditionalise()). The mixture is fitted
to the incomplete data by expectation-maximisation whose E-step uses each
row's observed margin and whose M-step restores the conditional covariance
of the filled entries, so component variances are not under-estimated.
Proper multiple imputation requires the fitting parameters themselves to
carry uncertainty, otherwise the pooled intervals are too narrow. Each of
the m imputations is therefore drawn under a mixture fitted to an
independent bootstrap resample of the rows, so proxy_pool() reflects both
imputation and parameter uncertainty.
The mechanism says how an entry came to be missing, which sets the
conditional the missing value is drawn from: mar() (the default) for missing
at random, censored() for a known interval such as a detection limit, or
mnar() for a value-dependent selection model. The interval and
value-dependent gates act on a single coordinate, and a row missing that
coordinate must have its other coordinates observed. Numeric data only;
categorical variables are out of scope.
A gmm_imputation object.
gmm_complete() to extract completions, proxy_pool() to pool an
estimand across them, gmm_conditionalise() for the conditioning algebra.
Other imputation:
as_mids(),
gmm_complete(),
gmm_imputation(),
mechanism,
proxy_fmi(),
proxy_mnar_sensitivity(),
proxy_pool()
set.seed(1) x1 <- rnorm(200) x2 <- x1 + rnorm(200) x2[runif(200) < plogis(x1)] <- NA # missing at random on x1 imp <- gmm_impute(cbind(x1, x2), N = 1L, m = 10L, seed = 1L) proxy_pool(imp, "x2")$estimate # pooled mean of x2set.seed(1) x1 <- rnorm(200) x2 <- x1 + rnorm(200) x2[runif(200) < plogis(x1)] <- NA # missing at random on x1 imp <- gmm_impute(cbind(x1, x2), N = 1L, m = 10L, seed = 1L) proxy_pool(imp, "x2")$estimate # pooled mean of x2
Returns the undirected second-order conditional-independence graph of a fitted
Gaussian mixture: the partial-correlation (Gaussian graphical model) structure
of the mixture's overall covariance. An edge is present when the
partial correlation of coordinates and given all the others
exceeds threshold in magnitude, and absent when it does not – the latter is
the Markov statement at second order.
The overall covariance
is closed-form in the mixture parameters, so no sampling is required.
gmm_independence_graph(g, threshold = 0.05)gmm_independence_graph(g, threshold = 0.05)
g |
|
threshold |
Non-negative partial-correlation magnitude above which an edge
is drawn. Defaults to |
This is a graphical-model (dependency-structure) diagnostic, not a causal
discovery method: it recovers the undirected Markov skeleton, not edge
directions. Its distinctive use is regime (iii): composed with
fit_kld_em(), it recovers the dependency structure of a target you can only
evaluate (an unnormalised energy / Gibbs density), where no sample exists to
hand a sampling-based estimator. Being second order, it sees dependencies that
enter the covariance; a purely higher-order coupling (zero correlation, nonzero
dependence) is not detected – raise the mixture's component count, or read the
coordinate-block dependence with gmm_mutual_information() instead.
A symmetric integer adjacency matrix (1 = edge, 0 = none) with the
coordinate names of g, carrying the partial-correlation matrix as the
"pcor" attribute.
gmm_mutual_information(), fit_kld_em(), gmm_conditionalise()
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
## Regime (iii): the Markov structure of an evaluable-but-unsampleable density. ## A continuous chain field x1 - x2 - x3 (couplings only between neighbours). energy <- function(X) { X <- matrix(X, ncol = 3) rowSums((X^2 - 1)^2) - 0.7 * (X[, 1] * X[, 2] + X[, 2] * X[, 3]) } target <- gmm_target(n_dim = 3L, log_density = function(X) -energy(X)) g <- fit_kld_em(target, N = 8L, proposal = is_uniform(3L, -3, 3), is_size = 8000L, anneal = TRUE, seed = 1L, support_warn = FALSE) gmm_independence_graph(g) # recovers x1 - x2 - x3 (no x1 - x3 edge)## Regime (iii): the Markov structure of an evaluable-but-unsampleable density. ## A continuous chain field x1 - x2 - x3 (couplings only between neighbours). energy <- function(X) { X <- matrix(X, ncol = 3) rowSums((X^2 - 1)^2) - 0.7 * (X[, 1] * X[, 2] + X[, 2] * X[, 3]) } target <- gmm_target(n_dim = 3L, log_density = function(X) -energy(X)) g <- fit_kld_em(target, N = 8L, proposal = is_uniform(3L, -3, 3), is_size = 8000L, anneal = TRUE, seed = 1L, support_warn = FALSE) gmm_independence_graph(g) # recovers x1 - x2 - x3 (no x1 - x3 edge)
Reads a fitted Gaussian mixture as a latent-class structural causal model
and returns the interventional distribution of the free coordinates under
do() of some coordinates, optionally conditioning on others.
gmm_intervene(g, do, given = NULL, ridge_eps = 1e-06)gmm_intervene(g, do, given = NULL, ridge_eps = 1e-06)
g |
|
do |
A length- |
given |
A length- |
ridge_eps |
Tiny ridge added to the conditional covariances for
numerical hygiene. Set to |
Intervened (do) coordinates are set inside every component but do not
re-weight the regime gate – this is the graph surgery that distinguishes
from . Conditioned
(given) coordinates re-weight the gate in the usual Bayesian way. Writing
the component prior as , the within-component conditional mean as
, and the given-coordinate evidence as , the returned
mixture has weights and per-component
parameters from the Schur conditional on the union of the do and given
coordinates.
For a joint fit over , gmm_intervene(fit, do = T = 1, given = X = x) is the do-response ; its mean
is , the latent-confounder-mode
interventional mean of proxy_cate.
A gmm over the free coordinates (those NA in both do and
given), with weights re-gated by the given evidence only.
gmm_counterfactual(), proxy_cate()
Other operators:
gmm_affine(),
gmm_aggregate(),
gmm_convolve(),
gmm_counterfactual(),
gmm_filter(),
gmm_missing(),
gmm_mix(),
gmm_observe(),
gmm_product(),
gmm_reduce()
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
## Joint (Y, T, X): set T = 1 while conditioning on X = 0.3. g <- gmm(weights = c(0.5, 0.5), means = list(c(0, 0, 0), c(2, 1, 1)), covariances = list(diag(3), diag(3))) gmm_intervene(g, do = c(NA, 1, NA), given = c(NA, NA, 0.3))## Joint (Y, T, X): set T = 1 while conditioning on X = 0.3. g <- gmm(weights = c(0.5, 0.5), means = list(c(0, 0, 0), c(2, 1, 1)), covariances = list(diag(3), diag(3))) gmm_intervene(g, do = c(NA, 1, NA), given = c(NA, NA, 0.3))
Estimates KL(p || q) between two Gaussian mixtures by Monte Carlo and,
optionally, evaluates the Hershey–Olsen variational approximation as a
deterministic sanity check.
gmm_kld(p, q, n_mc = 5000L, variational = TRUE)gmm_kld(p, q, n_mc = 5000L, variational = TRUE)
p, q
|
|
n_mc |
Number of Monte Carlo samples drawn from |
variational |
If |
The Monte Carlo estimator draws n_mc samples from p and returns the
empirical mean of log p(x) - log q(x), together with a Monte Carlo
standard error.
The variational approximation is
which is exact when p == q and tends to be a usable lower bound when
the components of p and q are well-separated. The closed-form
Gaussian–Gaussian KL KL(p_a || q_b) is used internally.
A list with components
mc - the Monte Carlo estimate of KL(p || q),
mc_se - its Monte Carlo standard error,
variational - the variational approximation (NA if
variational = FALSE),
n_mc - the number of Monte Carlo samples used.
Other ops:
dgmm(),
gmm_canonicalise(),
gmm_conditionalise(),
gmm_divergence(),
gmm_marginalise(),
gmm_mean(),
gmm_modes(),
pgmm(),
rgmm()
p <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) q <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(diag(2) * 2)) gmm_kld(p, q, n_mc = 500L)p <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) q <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(diag(2) * 2)) gmm_kld(p, q, n_mc = 500L)
Computes the marginal distribution of a Gaussian mixture over a subset of coordinates. The marginal of a Gaussian mixture is itself a Gaussian mixture with the same weights.
gmm_marginalise(g, keep)gmm_marginalise(g, keep)
g |
|
keep |
Integer vector of coordinate indices to retain (in |
A gmm object in dimension length(keep).
Other ops:
dgmm(),
gmm_canonicalise(),
gmm_conditionalise(),
gmm_divergence(),
gmm_kld(),
gmm_mean(),
gmm_modes(),
pgmm(),
rgmm()
g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0, 2), c(1, 0, -2)), covariances = list(diag(3), diag(3))) gmm_marginalise(g, keep = c(1L, 3L))g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0, 2), c(1, 0, -2)), covariances = list(diag(3), diag(3))) gmm_marginalise(g, keep = c(1L, 3L))
The exact first two moments of a mixture:
gmm_mean(g) gmm_cov(g)gmm_mean(g) gmm_cov(g)
g |
gmm_mean() returns a length-p numeric vector; gmm_cov()
returns a p by p numeric matrix.
Other ops:
dgmm(),
gmm_canonicalise(),
gmm_conditionalise(),
gmm_divergence(),
gmm_kld(),
gmm_marginalise(),
gmm_modes(),
pgmm(),
rgmm()
g <- gmm(weights = c(0.3, 0.7), means = list(c(-1, 0), c(1, 2)), covariances = list(diag(2), 0.5 * diag(2))) gmm_mean(g) gmm_cov(g)g <- gmm(weights = c(0.3, 0.7), means = list(c(-1, 0), c(1, 2)), covariances = list(diag(2), 0.5 * diag(2))) gmm_mean(g) gmm_cov(g)
A structured wrapper around gmm_conditionalise() for the common case
where the observed coordinates are specified by integer index rather
than NA-padded vector. Equivalent to gmm_observe() with a
selection matrix A and zero noise covariance, but routed through
the Schur-complement path for efficiency.
gmm_missing(g, observed, values)gmm_missing(g, observed, values)
g |
|
observed |
Integer vector of indices in |
values |
Numeric vector of length |
A gmm in R^(p - length(observed)).
Other operators:
gmm_affine(),
gmm_aggregate(),
gmm_convolve(),
gmm_counterfactual(),
gmm_filter(),
gmm_intervene(),
gmm_mix(),
gmm_observe(),
gmm_product(),
gmm_reduce()
g <- gmm(weights = c(0.4, 0.6), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) # Condition coord 2 on the value 0.5; keep coord 1. gmm_missing(g, observed = 2L, values = 0.5)g <- gmm(weights = c(0.4, 0.6), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) # Condition coord 2 on the value 0.5; keep coord 1. gmm_missing(g, observed = 2L, values = 0.5)
Flattens a list of Gaussian mixtures into a single mixture whose
density is the weighted average – model
averaging, prior pooling, or the mixture-of-mixtures construction.
gmm_mix(gmms, weights = NULL)gmm_mix(gmms, weights = NULL)
gmms |
A non-empty list of gmm (or gmm_fit) objects sharing one ambient dimension. |
weights |
Optional non-negative mixing weights, one per element of
|
A gmm with sum(K_b) components.
Other operators:
gmm_affine(),
gmm_aggregate(),
gmm_convolve(),
gmm_counterfactual(),
gmm_filter(),
gmm_intervene(),
gmm_missing(),
gmm_observe(),
gmm_product(),
gmm_reduce()
g1 <- gmm(weights = 1, means = list(-1), covariances = list(matrix(1))) g2 <- gmm(weights = 1, means = list(2), covariances = list(matrix(0.5))) gmm_mix(list(g1, g2), weights = c(0.7, 0.3))g1 <- gmm(weights = 1, means = list(-1), covariances = list(matrix(1))) g2 <- gmm(weights = 1, means = list(2), covariances = list(matrix(0.5))) gmm_mix(list(g1, g2), weights = c(0.7, 0.3))
Returns the distinct local modes of a Gaussian-mixture density by Gaussian mean-shift (the fixed-point hill-climb of Carreira-Perpinan 2000) started from each component mean, together with the mixture density at each mode. Nearby converged points are merged so that each genuine mode is reported once.
gmm_modes(object, starts = NULL, tol = 1e-05, dedup = NULL, max_iter = 200L)gmm_modes(object, starts = NULL, tol = 1e-05, dedup = NULL, max_iter = 200L)
object |
|
starts |
Optional |
tol |
Convergence tolerance on the mean-shift step length. Default
|
dedup |
Distance below which two converged points are treated as the
same mode. Default |
max_iter |
Maximum mean-shift iterations per start. Default |
A mixture of K components has at most K modes, and fewer when
components overlap; mean-shift from every component mean finds them
robustly without a grid. The companion of from_objective(): applied to
the fitted map it returns the recovered optima (ordered by density, which
for a Gibbs proxy ranks the deepest optima first).
A list with modes (an n-by-p matrix of distinct modes,
ordered by descending mixture density), density (the mixture density
at each mode), and n (the number of modes).
from_objective(), whose fitted map this resolves into optima.
Other ops:
dgmm(),
gmm_canonicalise(),
gmm_conditionalise(),
gmm_divergence(),
gmm_kld(),
gmm_marginalise(),
gmm_mean(),
pgmm(),
rgmm()
g <- gmm( weights = rep(1 / 3, 3), means = list(c(-3, 0), c(3, 0), c(0, 4)), covariances = rep(list(0.3 * diag(2)), 3) ) gmm_modes(g)$modesg <- gmm( weights = rep(1 / 3, 3), means = list(c(-3, 0), c(3, 0), c(0, 4)), covariances = rep(list(0.3 * diag(2)), 3) ) gmm_modes(g)$modes
Measures the dependence between two disjoint coordinate blocks of a fitted joint Gaussian mixture as the Cauchy-Schwarz divergence between the joint over the two blocks and the product of their marginals,
The product of the marginals is itself a Gaussian mixture, so the quantity is
closed-form. It is non-negative and zero exactly when the two blocks are
independent. (The naive combination is
not a valid mutual information: order-2 Renyi entropies are not additive
over independent blocks and that difference can be negative.)
gmm_mutual_information(g, block_a, block_b)gmm_mutual_information(g, block_a, block_b)
g |
|
block_a, block_b
|
Disjoint integer vectors of coordinate indices (in
|
A non-negative numeric scalar.
gmm_entropy(), gmm_divergence()
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
hellinger_mc(),
kld_trace(),
proxy_functional_ci()
## A correlated bivariate Gaussian: mutual information grows with |rho|. s <- matrix(c(1, 0.7, 0.7, 1), 2, 2) g <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(s)) gmm_mutual_information(g, 1L, 2L)## A correlated bivariate Gaussian: mutual information grows with |rho|. s <- matrix(c(1, 0.7, 0.7, 1), 2, 2) g <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(s)) gmm_mutual_information(g, 1L, 2L)
Number of components in a Gaussian mixture
gmm_n_components(x)gmm_n_components(x)
x |
Integer scalar.
Other classes:
autoplot.gmm_fit,
glance.gmm_fit,
gmm(),
gmm_counterfactual_law(),
gmm_dim(),
gmm_fit(),
gmm_target(),
gmm_weights(),
is_proposal(),
tidy.gmm
g <- gmm(weights = c(0.5, 0.5), means = list(c(0, 0), c(1, 1)), covariances = list(diag(2), diag(2))) gmm_n_components(g)g <- gmm(weights = c(0.5, 0.5), means = list(c(0, 0), c(1, 1)), covariances = list(diag(2), diag(2))) gmm_n_components(g)
Conditions a Gaussian mixture g on a single noisy linear observation
, .
Per component, applies the Kalman gain
and updates
Component weights are multiplied by the marginal evidence
and renormalised. This is
the finite-mixture analogue of a Kalman update step.
gmm_observe(g, A, y, noise_cov, b = 0, ridge_eps = 1e-06)gmm_observe(g, A, y, noise_cov, b = 0, ridge_eps = 1e-06)
g |
|
A |
An |
y |
A length- |
noise_cov |
An |
b |
Numeric scalar or length- |
ridge_eps |
Tiny ridge added to updated covariances for numerical
hygiene. Set to |
If the marginal evidence vanishes at every component (e.g. y is
many standard deviations from every component), the function issues a
warning and returns g unchanged with metadata$gmm_observe_no_update = TRUE.
A gmm in R^p with the same number of components and the
reweighted component weights.
Other operators:
gmm_affine(),
gmm_aggregate(),
gmm_convolve(),
gmm_counterfactual(),
gmm_filter(),
gmm_intervene(),
gmm_missing(),
gmm_mix(),
gmm_product(),
gmm_reduce()
g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) A <- matrix(c(1, 0), nrow = 1L) gmm_observe(g, A = A, y = 0.8, noise_cov = matrix(0.25, 1, 1))g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) A <- matrix(c(1, 0), nrow = 1L) gmm_observe(g, A = A, y = 0.8, noise_cov = matrix(0.25, 1, 1))
The normalised pointwise product of two mixture densities – the
conjugate Bayes update when one mixture plays the prior and the other
the likelihood. The product of two Gaussian mixtures is again a
Gaussian mixture with components:
with ,
, and
evaluated in
the log domain. The overall normaliser
is returned in the result's
metadata as log_integral (it is the marginal evidence of the update).
gmm_product(g1, g2, reduce = NULL)gmm_product(g1, g2, reduce = NULL)
g1, g2
|
|
reduce |
Optional positive integer: reduce the product to at most
this many components via |
Because the component count multiplies, chained products grow
geometrically; pass reduce to cap the count via gmm_reduce() after
the product (the standard assumed-density trick), or manage the budget
yourself.
A gmm with K1 * K2 components (or at most reduce), with
metadata$log_integral recording .
Other operators:
gmm_affine(),
gmm_aggregate(),
gmm_convolve(),
gmm_counterfactual(),
gmm_filter(),
gmm_intervene(),
gmm_missing(),
gmm_mix(),
gmm_observe(),
gmm_reduce()
prior <- gmm(weights = c(0.5, 0.5), means = list(-2, 2), covariances = list(matrix(1), matrix(1))) lik <- gmm(weights = 1, means = list(0.5), covariances = list(matrix(0.5))) post <- gmm_product(prior, lik) post@weightsprior <- gmm(weights = c(0.5, 0.5), means = list(-2, 2), covariances = list(matrix(1), matrix(1))) lik <- gmm(weights = 1, means = list(0.5), covariances = list(matrix(0.5))) post <- gmm_product(prior, lik) post@weights
Collapses a Gaussian mixture to at most k_max components. The default
method = "merge" is a greedy, moment-preserving pairwise merge: at each step
the cheapest pair of components is replaced by the single Gaussian that
preserves their combined weight, mean and covariance, until the component
budget is met. Because every merge is moment-preserving, the reduced mixture
has the same global mean and covariance as the original, and reducing all
the way to a single component returns the moment-matched Gaussian.
gmm_reduce( g, k_max, method = c("merge", "anneal"), cost = c("kl", "cs"), draws = 5000L, seed = NULL, ridge_eps = 0 )gmm_reduce( g, k_max, method = c("merge", "anneal"), cost = c("kl", "cs"), draws = 5000L, seed = NULL, ridge_eps = 0 )
g |
|
k_max |
Maximum number of components to keep (a positive integer). When
|
method |
|
cost |
The pairwise merge cost: |
draws |
Number of draws used by the |
seed |
Optional integer seed for the |
ridge_eps |
Ridge added to each merged covariance. The moment-preserving
merge is positive-definite by construction, so the default |
The merge cost decides which pair is collapsed first. cost = "kl" is the
Kullback-Leibler upper bound of Runnalls (2007), the standard mixture-
reduction criterion; cost = "cs" is the closed-form Cauchy-Schwarz
divergence between the two-component sub-mixture and its merge (the same
Gaussian-product identity that underlies gmm_divergence()), scaled by the
merged mass. Both are non-negative and zero for identical components.
method = "anneal" additionally draws a sample from the mixture and refits a
k_max-component proxy by annealed EM (see fit_em_samples()), then returns
whichever of the merge and the re-fit has the smaller Cauchy-Schwarz
divergence from the original. The re-fit can improve on the greedy merge for
smooth, over-parameterised mixtures, where a globally fitted proxy beats any
sequence of pairwise merges; the merge is returned when it is at least as
good, so the result is never worse than method = "merge". Unlike the merge,
the re-fit is a Monte Carlo fit and does not preserve the global moments
exactly; raise draws for a closer re-fit.
Reduction is the closing operation of a Gaussian-sum filter: repeated
gmm_observe() / gmm_affine() steps under a Gaussian-mixture noise or
dynamics model multiply the component count, and gmm_reduce() returns it to
a fixed budget.
A gmm with at most k_max components.
Runnalls, A. R. (2007) Kullback-Leibler approach to Gaussian mixture reduction. IEEE Transactions on Aerospace and Electronic Systems 43(3), 989–999. doi:10.1109/TAES.2007.4383588
Other operators:
gmm_affine(),
gmm_aggregate(),
gmm_convolve(),
gmm_counterfactual(),
gmm_filter(),
gmm_intervene(),
gmm_missing(),
gmm_mix(),
gmm_observe(),
gmm_product()
## A six-component mixture with three near-duplicate pairs. g <- gmm( weights = rep(1 / 6, 6), means = list(c(-4, 0), c(-4, 0.1), c(4, 0), c(4.1, 0), c(0, 5), c(0, 5.1)), covariances = rep(list(diag(2)), 6) ) gmm_reduce(g, k_max = 3L)## A six-component mixture with three near-duplicate pairs. g <- gmm( weights = rep(1 / 6, 6), means = list(c(-4, 0), c(-4, 0.1), c(4, 0), c(4.1, 0), c(0, 5), c(0, 5.1)), covariances = rep(list(diag(2)), 6) ) gmm_reduce(g, k_max = 3L)
An S7 representation of a target density that proxymix is asked to
approximate. A target may carry an evaluable log_density, a matrix of
i.i.d. samples, or both. Each of the three fitting regimes consumes a
different subset:
gmm_target( n_dim = integer(0), log_density = NULL, samples = NULL, support = NULL, normalised = NA, log_normalizer = NA_real_, name = "gmm_target", metadata = list() )gmm_target( n_dim = integer(0), log_density = NULL, samples = NULL, support = NULL, normalised = NA, log_normalizer = NA_real_, name = "gmm_target", metadata = list() )
n_dim |
Integer scalar — the ambient dimension |
log_density |
Optional function: |
samples |
Optional |
support |
Optional declaration of the target's support. |
normalised |
Logical scalar declaring whether |
log_normalizer |
Numeric scalar |
name |
Human-readable name. |
metadata |
Optional list of additional descriptors. |
regime "moment" needs samples (or both moments via metadata);
regime "sample" needs samples;
regime "kld" needs the log-density.
Use gmm_target() or gmm_target_from_samples() to construct.
Importance-sampled KLD-EM (regime "kld") only requires log_density
to be specified up to an unknown additive constant — the self-normalised
weights are invariant to scaling. The package's diagnostics downstream,
however, do depend on normalisation: an importance-sampled KLD estimate
against an unnormalised log-density measures
rather than
, and a squared-Hellinger Monte Carlo
estimate is only meaningful when both densities integrate to one.
Declare the target's normalisation explicitly via normalised (and,
where possible, supply log_normalizer) so that the package can label
shifted KLDs as shifted and refuse misleading Hellinger reports.
An S7 object of class gmm_target.
Other classes:
autoplot.gmm_fit,
glance.gmm_fit,
gmm(),
gmm_counterfactual_law(),
gmm_dim(),
gmm_fit(),
gmm_n_components(),
gmm_weights(),
is_proposal(),
tidy.gmm
tgt <- banana_target() tgttgt <- banana_target() tgt
gmm_target
Generic S3 constructor that turns a Bayesian posterior — represented
either by a fitted model object (e.g. from brms or Stan) or by a
bare callable — into a gmm_target suitable for regime (iii) of
fit_proxymix() / fit_kld_em().
gmm_target_from_posterior(model, ...) ## Default S3 method: gmm_target_from_posterior(model, ...) ## S3 method for class ''function'' gmm_target_from_posterior( model, ..., parameter_names = NULL, log_normalizer = NA_real_, name = NULL )gmm_target_from_posterior(model, ...) ## Default S3 method: gmm_target_from_posterior(model, ...) ## S3 method for class ''function'' gmm_target_from_posterior( model, ..., parameter_names = NULL, log_normalizer = NA_real_, name = NULL )
model |
One of:
|
... |
Forwarded to method-specific implementations. |
parameter_names |
Character vector of parameter names. Required
for the |
log_normalizer |
Numeric scalar |
name |
Optional human-readable target name. Defaults to
|
The contract for the underlying callable is:
Vectorised: accepts a numeric matrix with rows indexing
independent parameter draws and columns indexing parameters; returns
a length-nrow(theta) numeric vector of log p(theta | data) + const.
Unnormalised is fine: the marginal likelihood log Z is not
required. Where the source package can supply it, pass
log_normalizer.
Side-effect free: no plotting, no mutable state. Pure function.
Domain-safe: returns -Inf outside support rather than raising
an error.
The default method errors with a hint pointing the user at either
(a) a Bayesian package that registers a method, or (b) the
function method below.
A gmm_target with normalised = FALSE and the user-supplied
log_normalizer (or NA_real_).
# A trivial unnormalised log-posterior: a 2D banana centred near (1, 0). log_post <- function(theta) { x <- theta[, 1L] y <- theta[, 2L] -0.5 * (x^2 + (y - 0.1 * x^2 + 1)^2) } tgt <- gmm_target_from_posterior( log_post, parameter_names = c("x", "y") ) tgt# A trivial unnormalised log-posterior: a 2D banana centred near (1, 0). log_post <- function(theta) { x <- theta[, 1L] y <- theta[, 2L] -0.5 * (x^2 + (y - 0.1 * x^2 + 1)^2) } tgt <- gmm_target_from_posterior( log_post, parameter_names = c("x", "y") ) tgt
Wraps a numeric matrix of i.i.d. samples as a gmm_target. The resulting
target carries no log_density, so it can only feed regimes "moment"
(via empirical moments) and "sample" (classical EM).
gmm_target_from_samples(samples, name = "target_from_samples")gmm_target_from_samples(samples, name = "target_from_samples")
samples |
An |
name |
Optional human-readable name. Defaults to
|
A gmm_target object.
Other targets:
banana_target(),
donut_target(),
epanechnikov_target(),
maxent_target(),
mixture_target()
x <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(x) tgtx <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(x) tgt
Read-only accessors for the component weights, means, and covariances.
gmm_weights(g) gmm_means(g) gmm_covariances(g)gmm_weights(g) gmm_means(g) gmm_covariances(g)
g |
gmm_weights() returns a numeric vector of length K;
gmm_means() and gmm_covariances() return length-K lists of
length-p numeric vectors and p by p matrices respectively.
gmm_mean() / gmm_cov() for the moments of the mixture as a
whole, gmm_fit_quality() for the fit-quality certificate.
Other classes:
autoplot.gmm_fit,
glance.gmm_fit,
gmm(),
gmm_counterfactual_law(),
gmm_dim(),
gmm_fit(),
gmm_n_components(),
gmm_target(),
is_proposal(),
tidy.gmm
g <- gmm(weights = c(0.3, 0.7), means = list(-1, 2), covariances = list(matrix(1), matrix(0.5))) gmm_weights(g) gmm_means(g)g <- gmm(weights = c(0.3, 0.7), means = list(-1, 2), covariances = list(matrix(1), matrix(0.5))) gmm_weights(g) gmm_means(g)
Estimates the squared Hellinger distance H^2(f, g) = 1 - integral sqrt(f(x) g(x)) dx by importance sampling against the proposal stored
in the fit (for regime "kld") or by sampling from the fit itself (for
regime "sample"). The target's log_density must be supplied and
normalised; otherwise the Monte Carlo integral is biased by the
missing . When the target's normalised property is
not TRUE, a warning is issued and the returned value is flagged.
hellinger_mc(fit, n_mc = 5000L, seed = NULL)hellinger_mc(fit, n_mc = 5000L, seed = NULL)
fit |
A gmm_fit whose target carries a |
n_mc |
Number of Monte Carlo samples. |
seed |
Optional integer seed. |
A list with components
h2 - estimate of H^2(f, g),
se - Monte Carlo standard error,
n_mc - sample size used.
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
kld_trace(),
proxy_functional_ci()
fit <- fit_proxymix(banana_target(), N = 3L, regime = "kld", is_size = 2000L, max_iter = 25L, seed = 1L) hellinger_mc(fit, n_mc = 1000L, seed = 1L)fit <- fit_proxymix(banana_target(), N = 3L, regime = "kld", is_size = 2000L, max_iter = 25L, seed = 1L) hellinger_mc(fit, n_mc = 1000L, seed = 1L)
Runs stats::kmeans() on the supplied samples and uses the resulting
cluster centres and within-cluster covariances to seed an EM-style
fitter.
init_kmeans(samples, N = 2L, ridge_eps = 1e-06, nstart = 10L)init_kmeans(samples, N = 2L, ridge_eps = 1e-06, nstart = 10L)
samples |
An |
N |
Number of components. |
ridge_eps |
Ridge added to each cluster covariance for numerical stability when a cluster has fewer than two points. |
nstart |
|
A gmm of N components in dimension ncol(samples).
Other init:
init_moment_seed(),
init_random(),
init_warm_start(),
multi_start_best_of()
x <- matrix(stats::rnorm(200), ncol = 2) init_kmeans(x, N = 3L)x <- matrix(stats::rnorm(200), ncol = 2) init_kmeans(x, N = 3L)
Computes the global mean and covariance of the supplied samples and
spreads N components along the leading principal direction. Useful as
a deterministic starting point that survives multi-modal targets better
than a single-Gaussian fit.
init_moment_seed(samples, N = 2L, spread = 1.5)init_moment_seed(samples, N = 2L, spread = 1.5)
samples |
An |
N |
Number of components. |
spread |
Multiplier on the principal-direction standard deviation used to place the component means symmetrically about the global mean. |
A gmm of N components in dimension ncol(samples).
Other init:
init_kmeans(),
init_random(),
init_warm_start(),
multi_start_best_of()
x <- matrix(stats::rnorm(200), ncol = 2) init_moment_seed(x, N = 3L)x <- matrix(stats::rnorm(200), ncol = 2) init_moment_seed(x, N = 3L)
Generates an N-component random initialisation by perturbing isotropic
means around a centre. Useful as one starting point in a multi-start
best-of strategy.
init_random( N = 1L, p = 2L, centre = rep(0, p), scale = 1, sigma_diag = 1, seed = NULL )init_random( N = 1L, p = 2L, centre = rep(0, p), scale = 1, sigma_diag = 1, seed = NULL )
N |
Number of components. |
p |
Ambient dimension. |
centre |
Length- |
scale |
Standard deviation of the mean perturbation. |
sigma_diag |
Diagonal value used for the initial component covariances. |
seed |
Optional integer seed. |
A gmm of N components in dimension p.
Other init:
init_kmeans(),
init_moment_seed(),
init_warm_start(),
multi_start_best_of()
init_random(N = 3L, p = 2L, seed = 1L)init_random(N = 3L, p = 2L, seed = 1L)
Returns the input as-is. Provided as a name so that the multi-start driver can include "warm starts" by symbolic name.
init_warm_start(g)init_warm_start(g)
g |
The input g, validated.
Other init:
init_kmeans(),
init_moment_seed(),
init_random(),
multi_start_best_of()
g <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(diag(2))) init_warm_start(g)g <- gmm(weights = 1, means = list(c(0, 0)), covariances = list(diag(2))) init_warm_start(g)
Builds an is_proposal using a multivariate-normal N(mean, cov)
density and sampler.
is_mvn(n_dim, mean = rep(0, n_dim), cov = diag(n_dim))is_mvn(n_dim, mean = rep(0, n_dim), cov = diag(n_dim))
n_dim |
Ambient dimension |
mean |
Length- |
cov |
A |
An is_proposal object.
Other proposals:
is_mvt(),
is_uniform(),
proposal_uniform()
q <- is_mvn(n_dim = 2L, mean = c(0, 0), cov = 4 * diag(2)) qq <- is_mvn(n_dim = 2L, mean = c(0, 0), cov = 4 * diag(2)) q
Builds an is_proposal using a multivariate-Student-t density and
sampler with df degrees of freedom, location mean, and scale matrix
sigma. Heavier tails than is_mvn(), so often a safer importance
proposal at moderate dimensions.
is_mvt(n_dim, mean = rep(0, n_dim), sigma = diag(n_dim), df = 5)is_mvt(n_dim, mean = rep(0, n_dim), sigma = diag(n_dim), df = 5)
n_dim |
Ambient dimension |
mean |
Length- |
sigma |
A |
df |
Degrees of freedom ( |
An is_proposal object.
Other proposals:
is_mvn(),
is_uniform(),
proposal_uniform()
q <- is_mvt(n_dim = 2L, df = 5) qq <- is_mvt(n_dim = 2L, df = 5) q
An is_proposal packages a sampler with its corresponding log-density.
Pass one to fit_kld_em() (or fit_proxymix() with regime = "kld")
to plug an alternative proposal into the regime-(iii) loop.
is_proposal( n_dim = integer(0), sample = NULL, log_density = NULL, name = "is_proposal", metadata = list() )is_proposal( n_dim = integer(0), sample = NULL, log_density = NULL, name = "is_proposal", metadata = list() )
n_dim |
Integer scalar — the ambient dimension |
sample |
Function: |
log_density |
Function: |
name |
Human-readable name. |
metadata |
Optional list of additional descriptors. |
An S7 object of class is_proposal.
Other classes:
autoplot.gmm_fit,
glance.gmm_fit,
gmm(),
gmm_counterfactual_law(),
gmm_dim(),
gmm_fit(),
gmm_n_components(),
gmm_target(),
gmm_weights(),
tidy.gmm
q <- is_mvn(n_dim = 2L, mean = c(0, 0), cov = diag(2)) qq <- is_mvn(n_dim = 2L, mean = c(0, 0), cov = diag(2)) q
Builds an is_proposal that samples uniformly on the hyperrectangle
and reports the (constant) log-density on that box. Outside the box the
log-density is -Inf.
is_uniform(n_dim, lower = -1, upper = 1)is_uniform(n_dim, lower = -1, upper = 1)
n_dim |
Ambient dimension |
lower |
Length- |
upper |
Length- |
An is_proposal object.
Other proposals:
is_mvn(),
is_mvt(),
proposal_uniform()
q <- is_uniform(n_dim = 2L, lower = -5, upper = 5) q q@sample(3L)q <- is_uniform(n_dim = 2L, lower = -5, upper = 5) q q@sample(3L)
Returns the per-iteration estimate of KL(f || g_theta) produced during
a regime-(iii) fit, or NA for regimes that do not estimate the KLD
internally.
kld_trace(fit)kld_trace(fit)
fit |
A gmm_fit. |
Numeric vector (or NA_real_).
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
proxy_functional_ci()
fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1000L, max_iter = 15L, seed = 1L) kld_trace(fit)fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1000L, max_iter = 15L, seed = 1L) kld_trace(fit)
Builds the maximum-entropy gmm_target consistent with the supplied
constraints, the least-committal density given what is known. The maximum-
entropy density under linear constraints is an exponential family
on the support, and three cases admit
an exact closed form:
maxent_target(moments = NULL, support = NULL, name = "maxent_target")maxent_target(moments = NULL, support = NULL, name = "maxent_target")
moments |
Either |
support |
|
name |
Human-readable name. |
First- and second-moment constraints on full support – the Gaussian
. The moment constraints are
realised exactly, so a regime-(i) moment match recovers the target, and the
target carries its moments in metadata for that purpose.
First- and second-moment constraints on a box support – the same
canonical Gaussian form restricted to the box, a truncated Gaussian. The
normaliser is closed-form when cov is diagonal (a product of univariate
Gaussian box probabilities) and the target is then exactly normalised;
otherwise the target is declared unnormalised and regime (iii) fits it up to
the unknown constant. Truncation shifts the realised moments inward, so the
truncated density's mean and covariance are not mean and cov; it is the
canonical-form maximum-entropy density on the box, not the moment-matched
one.
A support constraint alone (no moments) on a finite box – the uniform
density, the maximum-entropy density on a compact support. Its differential
entropy is exactly , the largest
attainable on that support.
The bounded-support cases declare their support, so fit_kld_em() (and
fit_proxymix() with regime = "kld") selects a support-matched uniform
importance proposal automatically. Together with the Gaussian as the least-
committal full-support density and the epanechnikov_target() as a compact-
support obstruction, these complete a family of principled test targets.
A gmm_target.
Jaynes, E. T. (1957) Information theory and statistical mechanics. Physical Review 106(4), 620–630. doi:10.1103/PhysRev.106.620
Other targets:
banana_target(),
donut_target(),
epanechnikov_target(),
gmm_target_from_samples(),
mixture_target()
## Full-support second-moment maximum entropy is the Gaussian. g <- maxent_target(moments = list(mean = c(0, 0), cov = diag(2))) g@log_density(matrix(c(0, 0), nrow = 1L)) ## Support alone on a box is the uniform. u <- maxent_target(support = list(lower = 0, upper = 1)) exp(u@log_density(matrix(c(0.5), nrow = 1L))) ## Second moments on a box is a truncated Gaussian, fit via regime (iii). tg <- maxent_target(moments = list(mean = 0, cov = matrix(1)), support = list(lower = -2, upper = 2)) tg## Full-support second-moment maximum entropy is the Gaussian. g <- maxent_target(moments = list(mean = c(0, 0), cov = diag(2))) g@log_density(matrix(c(0, 0), nrow = 1L)) ## Support alone on a box is the uniform. u <- maxent_target(support = list(lower = 0, upper = 1)) exp(u@log_density(matrix(c(0.5), nrow = 1L))) ## Second moments on a box is a truncated Gaussian, fit via regime (iii). tg <- maxent_target(moments = list(mean = 0, cov = matrix(1)), support = list(lower = -2, upper = 2)) tg
Specifications passed to the mechanism argument of gmm_impute(). They
describe how an entry came to be missing, which sets the conditional the
missing value is drawn from.
mar() mnar(coord, beta, link = c("logit", "probit")) censored(coord, lower = -Inf, upper = Inf)mar() mnar(coord, beta, link = c("logit", "probit")) censored(coord, lower = -Inf, upper = Inf)
coord |
Name or index of the single coordinate the mechanism acts on. |
beta |
Sensitivity slope of the log-odds (or probit score) of being
missing in the missing value itself. Positive |
link |
Selection link, |
lower, upper
|
Bounds of the interval a censored missing entry is known to lie in. At least one must be finite. |
mar() is missing at random: the probability that an entry is missing may
depend on the observed entries but not on the missing value, so the imputation
conditional is the plain mixture conditional. This is the default.
censored() is a known interval. A missing entry of coord is known only to
lie in [lower, upper] – a detection limit (upper = LOD), a ceiling
(lower = cap), or interval censoring. The imputation conditional is the
mixture conditional truncated to that interval, which proxymix evaluates in
closed form, so the imputations respect the bound instead of substituting a
constant such as half the detection limit.
mnar() is missing not at random through a selection model: an entry of
coord is missing with probability in its own
unobserved value , where is the logistic or normal link. The
slope beta is the sensitivity parameter and is supplied, not estimated –
missing-not-at-random departures are not identified from the observed data, so
the appropriate use is to posit beta, propagate it, and report how conclusions
move with it (see proxy_mnar_sensitivity()). The intercept is calibrated to
the observed missingness rate. beta = 0 is missing at random.
A proxymix_gate object for gmm_impute().
gmm_impute(), proxy_mnar_sensitivity().
Other imputation:
as_mids(),
gmm_complete(),
gmm_imputation(),
gmm_impute(),
proxy_fmi(),
proxy_mnar_sensitivity(),
proxy_pool()
mar() censored("y", upper = 0.5) # a lower detection limit at 0.5 mnar("y", beta = 0.8) # larger y more likely missingmar() censored("y", upper = 0.5) # a lower detection limit at 0.5 mnar("y", beta = 0.8) # larger y more likely missing
A toy three-component planar mixture target where everything is known
exactly: the log_density matches the GMM density formula and the
attached samples are drawn from that same mixture. Useful for sanity-
checking the three fitting regimes against ground truth.
mixture_target(with_samples = FALSE, n = 2000L, seed = 1L)mixture_target(with_samples = FALSE, n = 2000L, seed = 1L)
with_samples |
If |
n |
Number of samples to attach when |
seed |
Optional integer seed used when drawing the samples. |
A gmm_target in dimension 2.
Other targets:
banana_target(),
donut_target(),
epanechnikov_target(),
gmm_target_from_samples(),
maxent_target()
m <- mixture_target(with_samples = TRUE, n = 100L) mm <- mixture_target(with_samples = TRUE, n = 100L) m
Runs the supplied fitter from each of several initialisations and returns the fit with the best score, following Karlis and Xekalaki (2003)'s recommendation.
multi_start_best_of(fit_fn, inits, score_fn, ...)multi_start_best_of(fit_fn, inits, score_fn, ...)
fit_fn |
A function with signature |
inits |
A list of gmm initialisations. |
score_fn |
A function |
... |
Additional arguments forwarded to |
The gmm_fit with the largest score_fn(fit).
Other init:
init_kmeans(),
init_moment_seed(),
init_random(),
init_warm_start()
x <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(x) inits <- list(init_random(2L, 2L, seed = 1L), init_moment_seed(x, N = 2L)) best <- multi_start_best_of( fit_fn = function(init, ...) fit_em_samples(tgt, init = init, ...), inits = inits, score_fn = function(fit) fit@diagnostics$loglik_final, max_iter = 25L ) best@diagnostics$loglik_finalx <- matrix(stats::rnorm(200), ncol = 2) tgt <- gmm_target_from_samples(x) inits <- list(init_random(2L, 2L, seed = 1L), init_moment_seed(x, N = 2L)) best <- multi_start_best_of( fit_fn = function(init, ...) fit_em_samples(tgt, init = init, ...), inits = inits, score_fn = function(fit) fit@diagnostics$loglik_final, max_iter = 25L ) best@diagnostics$loglik_final
The exact cumulative distribution function
of a
one-dimensional Gaussian mixture, and its inverse by monotone
root-finding. Together with dgmm() and rgmm() these complete the
usual d/p/q/r quartet for the one-dimensional case; for tail
probabilities of a multivariate mixture, marginalise first
(gmm_marginalise()) or push through the relevant linear functional
(gmm_affine()).
pgmm(q, g, lower.tail = TRUE) qgmm(p, g)pgmm(q, g, lower.tail = TRUE) qgmm(p, g)
q |
Numeric vector of quantiles. |
g |
|
lower.tail |
Logical; if |
p |
Numeric vector of probabilities in |
A numeric vector the length of the first argument.
Other ops:
dgmm(),
gmm_canonicalise(),
gmm_conditionalise(),
gmm_divergence(),
gmm_kld(),
gmm_marginalise(),
gmm_mean(),
gmm_modes(),
rgmm()
g <- gmm(weights = c(0.4, 0.6), means = list(-2, 1), covariances = list(matrix(0.5), matrix(1))) pgmm(c(-2, 0, 2), g) qgmm(c(0.1, 0.5, 0.9), g)g <- gmm(weights = c(0.4, 0.6), means = list(-2, 1), covariances = list(matrix(0.5), matrix(1))) pgmm(c(-2, 0, 2), g) qgmm(c(0.1, 0.5, 0.9), g)
proposal_uniform(), proposal_mvn(), and proposal_mvt() are the
preferred names of is_uniform(), is_mvn(), and is_mvt(): the
historical is_* prefix reads as a logical predicate, which these
constructors are not. The is_* names remain available as aliases and
are not scheduled for removal.
proposal_uniform(n_dim, lower = -1, upper = 1) proposal_mvn(n_dim, mean = rep(0, n_dim), cov = diag(n_dim)) proposal_mvt(n_dim, mean = rep(0, n_dim), sigma = diag(n_dim), df = 5)proposal_uniform(n_dim, lower = -1, upper = 1) proposal_mvn(n_dim, mean = rep(0, n_dim), cov = diag(n_dim)) proposal_mvt(n_dim, mean = rep(0, n_dim), sigma = diag(n_dim), df = 5)
n_dim |
Ambient dimension |
lower |
Length- |
upper |
Length- |
mean, cov
|
Forwarded to |
sigma, df
|
Forwarded to |
An is_proposal object.
Other proposals:
is_mvn(),
is_mvt(),
is_uniform()
Per-unit conditional average treatment effect , read in closed form off
the fitted joint mixture. Under the model's default "ignorability"
assumption this is the contrast of two component-gated conditional means;
under "latent_confounder" it is the regime-gated within-class slope (the
do-operator). The two coincide when treatment carries no information about
the regime beyond X; their difference is proxy_confounding_gap().
proxy_cate( model, newdata, t1 = 1, t0 = 0, se = TRUE, se_method = c("delta", "mc"), level = 0.95, B = 200L, scale = c("link", "response"), threshold = 0.5, ... )proxy_cate( model, newdata, t1 = 1, t0 = 0, se = TRUE, se_method = c("delta", "mc"), level = 0.95, B = 200L, scale = c("link", "response"), threshold = 0.5, ... )
model |
An uplift_model. |
newdata |
A data frame carrying the covariate columns. |
t1, t0
|
The treated and control treatment values. Default |
se |
Logical – compute standard errors and confidence intervals. |
se_method |
One of |
level |
Confidence level for the interval. Default |
B |
Number of bootstrap refits when |
scale |
One of |
threshold |
Decision threshold for the binary discretised predictive.
Default |
... |
Forwarded to |
The default delta-method standard error is the within-component prediction
variance, holding the regime gate fixed; it reduces to the ordinary
least-squares standard error of the treatment effect at K = 1. Set
se_method = "mc" for a resampling standard error that also reflects gate
uncertainty.
A data.table::data.table with columns id, tau, se,
ci_lo, ci_hi, overlap_flag.
proxy_decide(), proxy_confounding_gap(), proxy_overlap()
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) n <- 400L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + 0.5 * x + (1 + x) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 50L, seed = 1L) proxy_cate(m, newdata = data.frame(x = c(-1, 0, 1)))set.seed(1) n <- 400L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + 0.5 * x + (1 + x) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 50L, seed = 1L) proxy_cate(m, newdata = data.frame(x = c(-1, 0, 1)))
Per-unit difference between the ignorability-mode and do-mode effects,
. Under
ignorability the two coincide and ; a non-zero gap is a
sensitivity signal – how much the estimated effect would move if a
fitted regime confounded treatment and outcome beyond X – not a
correction the data licenses.
proxy_confounding_gap(model, newdata, t1 = 1, t0 = 0)proxy_confounding_gap(model, newdata, t1 = 1, t0 = 0)
model |
An uplift_model. |
newdata |
A data frame carrying the covariate columns. |
t1, t0
|
The treated and control treatment values. Default |
A data.table::data.table with columns id, tau_obs, tau_do,
gap, overlap_flag.
proxy_cate(), proxy_identification_report()
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) n <- 600L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 0.5 * t + x + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 80L, seed = 1L) proxy_confounding_gap(m, data.frame(x = c(-1, 0, 1)))set.seed(1) n <- 600L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 0.5 * t + x + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 80L, seed = 1L) proxy_confounding_gap(m, data.frame(x = c(-1, 0, 1)))
Turns the per-unit treatment effect into a next-best action under a linear
value model: treat when the value of the effect exceeds the cost, i.e.
, with
expected incremental value .
The standard error of tau is propagated to an action-flip probability –
the chance the recommended action would reverse under sampling noise.
proxy_decide( model, newdata, value, cost = 0, t1 = 1, t0 = 0, se_method = c("delta", "mc"), ... )proxy_decide( model, newdata, value, cost = 0, t1 = 1, t0 = 0, se_method = c("delta", "mc"), ... )
model |
An uplift_model. |
newdata |
A data frame carrying the covariate columns. |
value |
Numeric scalar – the value of one unit of outcome. |
cost |
Numeric scalar – the cost of treating one unit. Default |
t1, t0
|
The treated and control treatment values. Default |
se_method |
One of |
... |
Forwarded to |
A data.table::data.table with columns id, action,
expected_value, tau, se, flip_prob, overlap_flag.
proxy_cate(), proxy_policy_value()
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) n <- 400L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + (x > 0) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 50L, seed = 1L) proxy_decide(m, data.frame(x = c(-1, 1)), value = 1, cost = 0.2)set.seed(1) n <- 400L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + (x > 0) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 50L, seed = 1L) proxy_decide(m, data.frame(x = c(-1, 1)), value = 1, cost = 0.2)
The share of a column mean's total variance attributable to the missing
data, read from proxy_pool().
proxy_fmi(object, column, method = c("analytic", "rubin"))proxy_fmi(object, column, method = c("analytic", "rubin"))
object |
|
column |
Name of a single numeric column whose mean is pooled. |
method |
|
A named numeric scalar.
Other imputation:
as_mids(),
gmm_complete(),
gmm_imputation(),
gmm_impute(),
mechanism,
proxy_mnar_sensitivity(),
proxy_pool()
set.seed(1) x1 <- rnorm(150); x2 <- x1 + rnorm(150); x2[runif(150) < 0.3] <- NA imp <- gmm_impute(cbind(x1, x2), N = 1L, m = 10L, seed = 1L) proxy_fmi(imp, "x2")set.seed(1) x1 <- rnorm(150); x2 <- x1 + rnorm(150); x2[runif(150) < 0.3] <- NA imp <- gmm_impute(cbind(x1, x2), N = 1L, m = 10L, seed = 1L) proxy_fmi(imp, "x2")
Applies a functional to every member of a bootstrap ensemble and
returns the base fit's point estimate with percentile confidence
limits. The functional may return a scalar or a fixed-length numeric
vector – the moments (gmm_mean(), gmm_cov()), a tail probability
via pgmm() on a marginal, an entropy, a conditional mean, or any
composition of the operator calculus.
proxy_functional_ci(ensemble, fn, level = 0.9, ...)proxy_functional_ci(ensemble, fn, level = 0.9, ...)
ensemble |
A |
fn |
A function mapping a gmm to a numeric scalar or vector. |
level |
Confidence level. Default |
... |
Forwarded to |
A data frame with one row per element of fn's value:
term, estimate (the base fit's value), conf.low, conf.high.
Other diagnostics:
bic_aic(),
ess_summary(),
ess_trace(),
gmm_anneal_path(),
gmm_conditional_entropy(),
gmm_entropy(),
gmm_evidence(),
gmm_fit_ensemble(),
gmm_fit_quality(),
gmm_independence_graph(),
gmm_mutual_information(),
hellinger_mc(),
kld_trace()
fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1500L, max_iter = 20L, seed = 1L) ens <- gmm_fit_ensemble(fit, B = 30L, seed = 2L) proxy_functional_ci(ens, function(g) gmm_mean(g)[1L])fit <- fit_proxymix(banana_target(), N = 2L, regime = "kld", is_size = 1500L, max_iter = 20L, seed = 1L) ens <- gmm_fit_ensemble(fit, B = 30L, seed = 2L) proxy_functional_ci(ens, function(g) gmm_mean(g)[1L])
The differentiator: a structured audit of what the decision model identifies, what it assumes, and what it cannot answer. Carries the estimand, the identification regime and its requirement, the overlap rate on the supplied population, the confounding-gap magnitude (the value at risk from unobserved confounding), and the explicit non-identification of the individual counterfactual law.
proxy_identification_report(model, newdata, t1 = 1, t0 = 0)proxy_identification_report(model, newdata, t1 = 1, t0 = 0)
model |
An uplift_model. |
newdata |
A data frame carrying the covariate columns – the population the report is computed over. |
t1, t0
|
The treated and control treatment values. Default |
An S7 object of class uplift_identification with a print method.
proxy_confounding_gap(), proxy_overlap()
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) n <- 600L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 0.5 * t + x + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 80L, seed = 1L) proxy_identification_report(m, data.frame(x = stats::rnorm(100)))set.seed(1) n <- 600L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 0.5 * t + x + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 80L, seed = 1L) proxy_identification_report(m, data.frame(x = stats::rnorm(100)))
Sweeps the missing-not-at-random sensitivity slope beta over a grid and, at
each value, multiply-imputes coord under the selection model
and pools its mean by
Rubin's rules. The result traces how the estimate and its confidence interval
move as the assumed dependence of missingness on the unobserved value
strengthens, so an analyst can read off the value of beta at which a
conclusion would change. beta = 0 is the missing-at-random anchor.
proxy_mnar_sensitivity( data, coord, beta_grid = seq(0, 1, by = 0.25), link = c("logit", "probit"), N = NULL, m = 20L, seed = NULL, ... )proxy_mnar_sensitivity( data, coord, beta_grid = seq(0, 1, by = 0.25), link = c("logit", "probit"), N = NULL, m = 20L, seed = NULL, ... )
data |
A numeric matrix or data frame with |
coord |
Name or index of the coordinate the mechanism acts on. |
beta_grid |
Numeric vector of sensitivity slopes. Positive values make larger unobserved values more likely to be missing. |
link |
Selection link, |
N, m, seed, ...
|
Passed to |
The slope is a sensitivity parameter, not an estimate: the data do not identify it. Report the curve, not a single point.
A data frame with one row per grid value: beta, estimate,
std.error, conf.low, conf.high, fmi.
Other imputation:
as_mids(),
gmm_complete(),
gmm_imputation(),
gmm_impute(),
mechanism,
proxy_fmi(),
proxy_pool()
set.seed(1) x1 <- rnorm(300) y <- x1 + rnorm(300) y[runif(300) < plogis(-0.4 + 0.8 * y)] <- NA # MNAR on y dat <- data.frame(x1 = x1, y = y) proxy_mnar_sensitivity(dat, "y", beta_grid = c(0, 0.4, 0.8, 1.2), m = 10L, seed = 1L)set.seed(1) x1 <- rnorm(300) y <- x1 + rnorm(300) y[runif(300) < plogis(-0.4 + 0.8 * y)] <- NA # MNAR on y dat <- data.frame(x1 = x1, y = y) proxy_mnar_sensitivity(dat, "y", beta_grid = c(0, 0.4, 0.8, 1.2), m = 10L, seed = 1L)
Flags units whose (treatment, covariate) configuration is poorly covered
by the fitted joint – the proxy's mass coverage is the positivity
diagnostic. For each treatment arm the squared Mahalanobis distance to the
nearest regime centre is converted to an upper-tail chi-square coverage
probability; the reported coverage is the minimum across arms, since the
treatment effect needs both arms supported. Units below floor are flagged
and excluded from proxy_policy_value() by default.
proxy_overlap(model, newdata, t1 = 1, t0 = 0, floor = 0.01)proxy_overlap(model, newdata, t1 = 1, t0 = 0, floor = 0.01)
model |
An uplift_model. |
newdata |
A data frame carrying the covariate columns. |
t1, t0
|
The treated and control treatment values. Default |
floor |
Coverage probability below which a unit is flagged. Default
|
A data.table::data.table with columns id, coverage,
overlap_flag.
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) dat <- data.frame(y = stats::rnorm(200), t = stats::rbinom(200, 1L, 0.5), x = stats::rnorm(200)) m <- fit_uplift(dat, "y", "t", "x", N = 1L, regime = "moment") proxy_overlap(m, newdata = data.frame(x = c(0, 8)))set.seed(1) dat <- data.frame(y = stats::rnorm(200), t = stats::rbinom(200, 1L, 0.5), x = stats::rnorm(200)) m <- fit_uplift(dat, "y", "t", "x", N = 1L, regime = "moment") proxy_overlap(m, newdata = data.frame(x = c(0, 8)))
Estimates the expected value of deploying a per-unit targeting policy,
, from the fitted model alone – no live A/B test. Units that
fail the overlap diagnostic are excluded by default and their count is
reported, never silently dropped.
proxy_policy_value( model, newdata, policy, value, cost = 0, t1 = 1, t0 = 0, exclude_low_overlap = TRUE )proxy_policy_value( model, newdata, policy, value, cost = 0, t1 = 1, t0 = 0, exclude_low_overlap = TRUE )
model |
An uplift_model. |
newdata |
A data frame carrying the covariate columns – the population the policy would be deployed on. |
policy |
A per-unit action specification: a 0/1 vector of length
|
value |
Numeric scalar – the value of one unit of outcome. |
cost |
Numeric scalar – the cost of treating one unit. Default |
t1, t0
|
The treated and control treatment values. Default |
exclude_low_overlap |
Logical – drop overlap-flagged units from the
average (and report the count). Default |
A one-row data.table::data.table with columns policy_value,
n_used, n_excluded, n_treated.
proxy_decide(), proxy_overlap()
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) n <- 600L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + (0.4 + x) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 80L, seed = 1L) nd <- data.frame(x = stats::rnorm(200)) proxy_policy_value(m, nd, policy = "optimal", value = 1, cost = 0.3)set.seed(1) n <- 600L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + (0.4 + x) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 80L, seed = 1L) nd <- data.frame(x = stats::rnorm(200)) proxy_policy_value(m, nd, policy = "optimal", value = 1, cost = 0.3)
Pools the mean of one column over the m completed datasets in a
gmm_imputation, returning the estimate with a standard error, degrees of
freedom, confidence interval, and fraction of missing information. The
default method = "analytic" computes the between-imputation variance in
closed form – the exact limit, with no Monte-Carlo
noise – from the mixture conditional, and splits the total variance into
complete-data, imputation, and parameter parts. method = "rubin" instead
applies Rubin's rules to the drawn completions (useful as a check).
proxy_pool(object, column, method = c("analytic", "rubin"))proxy_pool(object, column, method = c("analytic", "rubin"))
object |
|
column |
Name of a single numeric column whose mean is pooled. |
method |
|
For a regression or any other model estimand, do not pool here: convert the
imputations to a mice object with as_mids() and pool with
mice::pool(), which is the established workflow and reports the same
diagnostics.
A one-row data frame: term, estimate, std.error,
statistic, df, conf.low, conf.high, fmi.
proxy_fmi(), as_mids() to pool models with mice::pool().
Other imputation:
as_mids(),
gmm_complete(),
gmm_imputation(),
gmm_impute(),
mechanism,
proxy_fmi(),
proxy_mnar_sensitivity()
set.seed(1) x1 <- rnorm(150); x2 <- x1 + rnorm(150) x2[runif(150) < 0.3] <- NA imp <- gmm_impute(cbind(x1, x2), N = 1L, m = 10L, seed = 1L) proxy_pool(imp, "x2") # analytic column meanset.seed(1) x1 <- rnorm(150); x2 <- x1 + rnorm(150) x2[runif(150) < 0.3] <- NA imp <- gmm_impute(cbind(x1, x2), N = 1L, m = 10L, seed = 1L) proxy_pool(imp, "x2") # analytic column mean
Per-unit predicted outcome – the first rung
of the ladder, risk / response scoring. Under "ignorability" this is the
component-gated conditional mean; under "latent_confounder" it is the
regime-gated interventional mean. For a binary outcome with
scale = "response" the prediction is the discretised predictive
probability P(Y > threshold).
proxy_predict( model, newdata, t, scale = c("link", "response"), threshold = 0.5 )proxy_predict( model, newdata, t, scale = c("link", "response"), threshold = 0.5 )
model |
An uplift_model. |
newdata |
A data frame carrying the covariate columns. |
t |
The treatment value to predict the outcome under. |
scale |
One of |
threshold |
Decision threshold for the binary discretised predictive.
Default |
A data.table::data.table with columns id and prediction.
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) dat <- data.frame(y = stats::rnorm(200), t = stats::rbinom(200, 1L, 0.5), x = stats::rnorm(200)) m <- fit_uplift(dat, "y", "t", "x", N = 1L, regime = "moment") proxy_predict(m, data.frame(x = c(-1, 0, 1)), t = 1)set.seed(1) dat <- data.frame(y = stats::rnorm(200), t = stats::rbinom(200, 1L, 0.5), x = stats::rnorm(200)) m <- fit_uplift(dat, "y", "t", "x", N = 1L, regime = "moment") proxy_predict(m, data.frame(x = c(-1, 0, 1)), t = 1)
Exposes the K mixture components as decision segments: each regime's
prevalence (weight), its within-segment treatment effect (the within-class
treatment slope), its residual standard deviation, and its covariate centre.
This is the interpretable by-product the closed-form reading gives for free.
proxy_regime_segments(model, t1 = 1, t0 = 0)proxy_regime_segments(model, t1 = 1, t0 = 0)
model |
An uplift_model. |
t1, t0
|
The treated and control treatment values used to scale the
within-segment effect. Default |
A data.table::data.table with columns regime, weight,
effect, sigma, and one column per covariate centre.
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) n <- 600L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + (0.5 + x) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 80L, seed = 1L) proxy_regime_segments(m)set.seed(1) n <- 600L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + (0.5 + x) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 80L, seed = 1L) proxy_regime_segments(m)
For each observed unit (y, t, x), the counterfactual-mean uplift of moving
from t0 to t1, ,
computed by gmm_counterfactual(). Unlike proxy_cate(), the abduction
gate uses the observed outcome y as well, sharpening the per-unit estimate.
Only the counterfactual mean is identified; the spread is not (see
gmm_cf_variance()).
proxy_retrospective_uplift(model, observed, t1 = 1, t0 = 0)proxy_retrospective_uplift(model, observed, t1 = 1, t0 = 0)
model |
An uplift_model. |
observed |
A data frame carrying the outcome, treatment, and covariate columns of the observed units. |
t1, t0
|
The treated and control treatment values. Default |
A data.table::data.table with columns id, y_obs, t_obs,
cf_mean_t1, retro_uplift.
gmm_counterfactual(), proxy_cate()
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) n <- 400L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + (0.5 + x) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 80L, seed = 1L) proxy_retrospective_uplift(m, observed = dat[1:5, ])set.seed(1) n <- 400L x <- stats::rnorm(n) t <- stats::rbinom(n, 1L, 0.5) y <- 1 + (0.5 + x) * t + stats::rnorm(n, sd = 0.5) dat <- data.frame(y = y, t = t, x = x) m <- fit_uplift(dat, "y", "t", "x", N = 2L, regime = "sample", max_iter = 80L, seed = 1L) proxy_retrospective_uplift(m, observed = dat[1:5, ])
proxy_cate() for a binary treatment)For a binary treatment, the uplift is exactly the conditional average
treatment effect. This is a thin alias of proxy_cate() kept for the
next-best-action vocabulary.
proxy_uplift(model, newdata, ...)proxy_uplift(model, newdata, ...)
model |
An uplift_model. |
newdata |
A data frame carrying the covariate columns. |
... |
Forwarded to |
A data.table::data.table – see proxy_cate().
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
uplift_identification(),
uplift_model()
set.seed(1) dat <- data.frame(y = stats::rnorm(200), t = stats::rbinom(200, 1L, 0.5), x = stats::rnorm(200)) m <- fit_uplift(dat, "y", "t", "x", N = 1L, regime = "moment") proxy_uplift(m, newdata = data.frame(x = 0))set.seed(1) dat <- data.frame(y = stats::rnorm(200), t = stats::rbinom(200, 1L, 0.5), x = stats::rnorm(200)) m <- fit_uplift(dat, "y", "t", "x", N = 1L, regime = "moment") proxy_uplift(m, newdata = data.frame(x = 0))
Draws n independent samples from a Gaussian mixture.
rgmm(n, g)rgmm(n, g)
n |
Number of samples (positive integer scalar). |
g |
A numeric matrix of dimension n by p.
Other ops:
dgmm(),
gmm_canonicalise(),
gmm_conditionalise(),
gmm_divergence(),
gmm_kld(),
gmm_marginalise(),
gmm_mean(),
gmm_modes(),
pgmm()
g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) x <- rgmm(50L, g) dim(x)g <- gmm(weights = c(0.5, 0.5), means = list(c(-1, 0), c(1, 0)), covariances = list(diag(2), diag(2))) x <- rgmm(50L, g) dim(x)
Fits every candidate component count and chooses one by a
regime-appropriate criterion. With samples (regime ii) the choice is
the smallest BIC. With an evaluable-only target (regime iii) each
candidate is scored by its held-out validation KLD – an independent
importance draw the fit never trained on – and the choice follows the
one-standard-error rule: the smallest N whose validation score is
within one Monte Carlo standard error of the best score. The scored
table is returned alongside the choice, and callers who prefer to
choose by eye can ignore the recommendation.
select_N( target, candidates = 1:6, regime = c("auto", "sample", "kld"), seed = NULL, ... )select_N( target, candidates = 1:6, regime = c("auto", "sample", "kld"), seed = NULL, ... )
target |
A gmm_target. |
candidates |
Integer vector of component counts to try. |
regime |
|
seed |
Optional integer seed shared across candidates (paired fits). |
... |
Forwarded to the regime's fitter ( |
A list of class proxymix_selection: best_n (the chosen
count), best_fit (its gmm_fit), and table (one row per
candidate with the criterion values).
Other fitting:
fit_em_samples(),
fit_kld_em(),
fit_moment_match(),
from_kde(),
from_objective()
sel <- select_N(banana_target(), candidates = 1:3, is_size = 1500L, max_iter = 20L, seed = 1L) sel$table sel$best_nsel <- select_N(banana_target(), candidates = 1:3, is_size = 1500L, max_iter = 20L, seed = 1L) sel$table sel$best_n
A broom-style tidy() method: one row per component, with the weight,
the mean coordinates (mean_1, ...), and the marginal variances
(var_1, ...). Available as generics::tidy(g) (or broom::tidy(g))
when the generics package is installed.
x |
|
... |
Ignored, for generic compatibility. |
A data frame with K rows.
Other classes:
autoplot.gmm_fit,
glance.gmm_fit,
gmm(),
gmm_counterfactual_law(),
gmm_dim(),
gmm_fit(),
gmm_n_components(),
gmm_target(),
gmm_weights(),
is_proposal()
g <- gmm(weights = c(0.3, 0.7), means = list(c(-1, 0), c(2, 1)), covariances = list(diag(2), 0.5 * diag(2))) generics::tidy(g)g <- gmm(weights = c(0.3, 0.7), means = list(c(-1, 0), c(2, 1)), covariances = list(diag(2), 0.5 * diag(2))) generics::tidy(g)
The structured return type of proxy_identification_report(). Print it for
the executive one-pager.
uplift_identification( estimand = character(0), assume = character(0), n_units = integer(0), overlap_pct = numeric(0), confounding_gap_mean = numeric(0), confounding_gap_max = numeric(0), K = integer(0), outcome_type = "continuous" )uplift_identification( estimand = character(0), assume = character(0), n_units = integer(0), overlap_pct = numeric(0), confounding_gap_mean = numeric(0), confounding_gap_max = numeric(0), K = integer(0), outcome_type = "continuous" )
estimand |
Character – the target estimand. |
assume |
Character – the identification regime. |
n_units |
Integer – units the report covers. |
overlap_pct |
Numeric – percentage of units with adequate overlap. |
confounding_gap_mean, confounding_gap_max
|
Numeric – mean and maximum absolute confounding gap over the population. |
K |
Integer – the number of fitted regimes. |
outcome_type |
Character – the outcome scale. |
An S7 object of class uplift_identification.
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_model()
The object returned by fit_uplift(): a joint gmm_fit over
(outcome, treatment, covariates) together with the column roles, the
identification assumption it will be read under, the outcome type, and the
training sample (retained so that resampling standard errors and overlap
diagnostics are available). The decision verbs dispatch on this class.
uplift_model( fit = NULL, roles = list(), assume = "ignorability", outcome_type = "continuous", data = NULL, n_train = integer(0), treatment_levels = c(0, 1), name = "uplift_model", metadata = list() )uplift_model( fit = NULL, roles = list(), assume = "ignorability", outcome_type = "continuous", data = NULL, n_train = integer(0), treatment_levels = c(0, 1), name = "uplift_model", metadata = list() )
fit |
The joint gmm_fit over the stacked |
roles |
A list with integer indices |
assume |
One of |
outcome_type |
One of |
data |
The |
n_train |
Integer scalar – the training sample size. |
treatment_levels |
Numeric length-2 vector |
name |
Human-readable name. |
metadata |
Optional list of descriptors (e.g. the K-selection trace). |
An S7 object of class uplift_model.
Other decision:
fit_uplift(),
gmm_cf_mean(),
gmm_cf_tail_prob(),
gmm_cf_variance(),
gmm_counterfactual(),
gmm_intervene(),
proxy_cate(),
proxy_confounding_gap(),
proxy_decide(),
proxy_identification_report(),
proxy_overlap(),
proxy_policy_value(),
proxy_predict(),
proxy_regime_segments(),
proxy_retrospective_uplift(),
proxy_uplift(),
uplift_identification()