mixle.stats.combinator.copula module¶
Copula combinator: glue arbitrary marginal distributions to a dependence structure (Sklar’s theorem).
GaussianCopulaDistribution (mixle.stats.multivariate) models only dependence, on the unit cube
(0,1)^d – it assumes its inputs are already the uniform scores u_i. This combinator is the piece
that makes copulas composable: give it your CONTINUOUS marginals (any mixle leaves exposing cdf –
a Gamma, a StudentT, a VonMises, any continuous family mixed freely) and a copula core, and it forms the
joint
f(x_1, …, x_d) = c(F_1(x_1), …, F_d(x_d)) * prod_i f_i(x_i) (Sklar)
where each F_i = marginals[i].cdf is the probability-integral transform (PIT) and c is the copula
density. That is the whole point of copulas: pick any marginals you like and couple them through one
dependence object, instead of hand-writing a bespoke multivariate leaf for every marginal combination.
This continuous-Sklar formula is only valid when every f_i is a genuine density. A DISCRETE marginal’s
log_density is a probability MASS, not a density; plugging a mass into the continuous copula-density
formula over/under-counts and the resulting “probabilities” no longer sum to 1 (two Bernoulli(0.5) margins
coupled by a correlated Gaussian copula, e.g., report outcome probabilities summing to roughly 2.5e8, not
1). The mathematically correct joint for a discrete or mixed marginal instead needs copula-CDF rectangle
differences (inclusion-exclusion over C, not c, at the corners of each discrete cell) – none of
this combinator’s copula cores (Gaussian/Clayton/Frank/Student-t/vine) currently expose a CDF, so rather
than silently producing an invalid probability model, CopulaDistribution.__init__ rejects any marginal
with enumerable (discrete/atomic) support. Discrete/mixed marginals are not yet supported.
Estimation is IFM (Inference Functions for Margins): fit each marginal on its own column, PIT the data through the fitted marginals, then fit the copula on the uniform scores. This is exact in a single M-step (the accumulator buffers the raw columns, the same pattern the neural leaves use), not an approximate coupled iteration.
The copula core is pluggable: any distribution on (0,1)^d implementing the mixle five-piece contract
works, as long as it also exposes a dim attribute matching len(marginals) (checked at construction).
GaussianCopulaDistribution is the first supported
core; Clayton/Frank/t cores can be dropped in later with no change here.
Reference: Nelsen, An Introduction to Copulas (2nd ed., Springer, 2006); Joe, Dependence Modeling with Copulas (CRC, 2014).
- class CopulaIFMStatistics(schema_version, marginal_statistics, columns, weights, marginal_effective_count, copula_effective_count)[source]
Bases:
NamedTupleVersioned IFM state with explicit stage-specific effective counts.
- Parameters:
- schema_version: int
Alias for field number 0
- columns: ndarray
Alias for field number 2
- weights: ndarray
Alias for field number 3
- marginal_effective_count: float
Alias for field number 4
- copula_effective_count: float
Alias for field number 5
- exception CopulaQuantileError[source]
Bases:
RuntimeErrorRaised when a marginal quantile violates its declared CDF inverse contract.
- class CopulaDistribution(marginals, copula, name=None, keys=None)[source]
Bases:
SequenceEncodableProbabilityDistributionJoint over
dscalar fields =dmarginals coupled by a copula core (Sklar’s theorem).marginalsis a length-dsequence of CONTINUOUS mixle leaves, each exposinglog_density, deterministiccdf/quantilemethods, and the estimator/encoder contract – a marginal with enumerable (discrete/atomic) support is rejected at construction (see module docstring: the continuous Sklar density formula this class implements is not a valid probability model for discrete marginals).copulais a distribution on(0,1)^d(e.g.GaussianCopulaDistribution) whosedimmust equallen(marginals). An observation is a length-dtuple/array of scalars(x_1, ..., x_d).- Parameters:
- density(x)[source]
Return the joint density at one raw observation.
- log_density(x)[source]
Sklar’s decomposition: sum of marginal log-densities + the copula log-density at the PIT scores.
- seq_log_density(enc)[source]
Vectorized: per-column marginal log-densities (summed) plus the copula log-density at the PIT scores.
- sampler(seed=None)[source]
Return a sampler that draws copula scores and inverts the marginals.
- Parameters:
seed (int | None)
- Return type:
CopulaSampler
- estimator(pseudo_count=None)[source]
Return an IFM estimator for marginals followed by the copula core.
- Parameters:
pseudo_count (float | None)
- Return type:
CopulaEstimator
- dist_to_encoder()[source]
Return an encoder that preserves marginal encodings and raw columns.
- Return type:
CopulaDataEncoder
- class CopulaSampler(dist, seed=None)[source]
Bases:
DistributionSamplerSample by drawing uniform scores and applying each marginal’s deterministic quantile.
- Parameters:
dist (CopulaDistribution)
seed (int | None)
- class CopulaDataEncoder(marginal_encoders)[source]
Bases:
DataSequenceEncoderEncode a batch as
(per-marginal encodings, raw (n, d) column array).The raw columns ride along because the copula’s uniform scores
u = F(x)depend on the marginals’ current parameters (they change during fitting), so they cannot be baked in at encode time – they are recomputed byCopulaDistribution._pit_columns()against whatever distribution is scoring/estimating.- Parameters:
marginal_encoders (Sequence[DataSequenceEncoder])
- class CopulaAccumulator(marginal_accumulators, dim, keys=None)[source]
Bases:
SequenceEncodableStatisticAccumulatorDelegate per-column sufficient stats to marginal sub-accumulators; buffer raw columns for the copula.
The copula stage is fit AFTER the marginals (IFM): it needs the marginals’ fitted CDFs to PIT the data, so the raw columns are buffered (weighted) here and PIT-ed inside
CopulaEstimator.estimate(). This is the same buffer-the-rows pattern the neural leaves use, and it makes the IFM fit exact in one M-step.- update(x, weight, estimate)[source]
Update marginal accumulators and buffer one raw observation for IFM copula fitting.
- initialize(x, weight, rng)[source]
Initialize marginal accumulators and buffer one raw observation.
- Parameters:
weight (float)
rng (RandomState | None)
- Return type:
None
- seq_update(enc, weights, estimate)[source]
Update marginal accumulators and buffer encoded raw columns for IFM.
- seq_initialize(enc, weights, rng)[source]
Initialize marginal accumulators and buffer encoded raw columns.
- Parameters:
enc (Any)
weights (ndarray)
rng (RandomState | None)
- Return type:
None
- combine(suff_stat)[source]
Merge marginal sufficient statistics and buffered raw columns.
- Parameters:
suff_stat (CopulaIFMStatistics)
- Return type:
CopulaAccumulator
- value()[source]
Return marginal stats, buffered raw columns, and buffered weights.
- Return type:
CopulaIFMStatistics
- from_value(x)[source]
Restore marginal stats and raw-column buffers from
valueoutput.- Parameters:
x (CopulaIFMStatistics)
- Return type:
CopulaAccumulator
- key_merge(stats_dict)[source]
Delegate keyed merges to marginal accumulators.
- key_replace(stats_dict)[source]
Delegate keyed replacements to marginal accumulators.
- acc_to_encoder()[source]
Return an encoder composed from the marginal accumulator encoders.
- Return type:
CopulaDataEncoder
- class CopulaAccumulatorFactory(marginal_factories, dim, keys=None)[source]
Bases:
StatisticAccumulatorFactoryCreate accumulators for IFM copula estimation.
- make()[source]
Create an empty copula accumulator.
- Return type:
CopulaAccumulator
- class CopulaEstimator(marginal_estimators, copula_estimator, dim, copula_prototype, name=None, keys=None)[source]
Bases:
ParameterEstimatorIFM estimator: fit each marginal from its sub-stats, PIT the buffered data, fit the copula on the scores.
- Parameters:
- accumulator_factory()[source]
Return a factory for IFM copula sufficient-statistic accumulators.
- Return type:
CopulaAccumulatorFactory