mixle.inference.glm module¶
Generalized linear models and penalized / robust / quantile regression on plain arrays.
A array-level regression toolkit (operating on a design matrix X and response y, independent of
the PPL DSL in mixle.ppl.regression):
glm()– exponential-family GLMs by iteratively reweighted least squares, with explicit family/link objects (Gaussian, Binomial, Poisson, Gamma, inverse-Gaussian, negative-binomial), offsets, prior weights under a stated convention (weight_type: analytic precision weights by default, frequency counts on request), and optional sandwich (robust) standard errors in the HC0-HC3 leverage-corrected variants.
ridge_regression(),elastic_net()(andlasso()) – L2 / L1 / mixed penalised linear regression; the elastic net is solved by coordinate descent.
robust_regression()– Huber / Tukey M-estimation, down-weighting outliers via IRLS on a robust scale.
quantile_regression()– the conditionaltau-quantile by IRLS on the check loss.
glm returns a result with coefficients, standard errors, and Wald inference; the penalized,
robust, and quantile fits return coefficients and fits WITHOUT standard errors (their correct
inferential machinery – debiased lasso, M-estimator sandwiches, quantile sparsity estimates –
is deliberately not faked here; audit G-6).
- class Link(name, g, inv, mu_eta)[source]
Bases:
objectA link function
eta = g(mu)with its inverse and derivativedmu/deta.
- class Family(name, variance, canonical, unit_deviance, estimate_dispersion, extra=1.0, default_link=None)[source]
Bases:
objectAn exponential-family error model: variance function, canonical link, deviance, dispersion.
canonicalnames the family’s mathematical canonical link;default_link(when set) is the linkglm()fits with when none is requested. They are separate so families whose canonical link is numerically awkward (gamma’sinverse, inverse-Gaussian’sinverse_squared– neither keepsmupositive) can default tologwithout mislabeling the canonical link.
- class GLMResult(coef, se, fitted, deviance, dispersion, log_likelihood, n_iter, family, link, cov, converged=True, rank=None, residual_df=None, dispersion_estimated=False, weight_type='analytic', ll_nobs=None, separated=False, cov_type='model', _link=None)[source]
Bases:
objectFitted GLM.
- Parameters:
coef (ndarray)
se (ndarray)
fitted (ndarray)
deviance (float)
dispersion (float)
log_likelihood (float | None)
n_iter (int)
family (str)
link (str)
cov (ndarray)
converged (bool)
rank (int | None)
residual_df (int | None)
dispersion_estimated (bool)
weight_type (str)
ll_nobs (float | None)
separated (bool)
cov_type (str)
_link (Link)
- coef
(p,)coefficient estimates.- Type:
- se
(p,)standard errors (model-based, or the robust variant named bycov_type). All NaN on a saturated dispersion-estimating fit – seedispersion.- Type:
- cov_type
which estimator
se/covcame from:"model"forphi (X'WX)^-1, or"HC0"|"HC1"|"HC2"|"HC3"for the sandwich variants (seeglm()’srobustargument). Recorded on the result for the same reasonweight_typeis: the meaning of a headline output must be readable off the result.- Type:
- fitted
(n,)fitted meansmu.- Type:
- deviance
residual deviance.
- Type:
- dispersion
estimated/assumed dispersion
phi– theresidual_df-corrected (Pearson) estimate the standard errors use, NOT the value the log-likelihood is evaluated at. NaN when a dispersion-estimating family is fit withresidual_df <= 0(a SATURATED fit – as many estimated parameters as observations): the coefficients, fitted values and deviance are still returned, but the dispersion, every standard error and the likelihood are undefined there, announced by aUserWarningat fit time, andz_values/p_values/aic/bicrefuse with that reason.- Type:
- residual_df
residual degrees of freedom,
n - rank, wherencounts rows underweight_type="analytic"andsum(weights)underweight_type="frequency". This is the divisor ofdispersionand the t referencep_valuesuses, so it is where the weight convention shows up in the standard errors.- Type:
int | None
- log_likelihood
maximised log-likelihood, or
Nonewhen the supplied family/response does not define one – or when the fit is saturated (seedispersion), where the likelihood is unbounded in the dispersion and so has no maximised value. For dispersion-estimating families this is evaluated at the family’s own dispersion MLE (see_dispersion_mle), which differs fromdispersionby design: the covariance wants the df-corrected estimate, the likelihood wants its maximiser. It is also computed underweight_type: analytic weights enter as per-observation precisions (Var = phi / w_i), frequency weights as replicate counts.- Type:
float | None
- ll_nobs
how many observations
log_likelihoodis a sum over – the sample sizebicpenalises with. Row count for an analytic-weighted dispersion-estimating family;sum(weights)whenever the likelihood is a weighted sum of per-unit densities (every frequency-weighted fit, and every fixed-dispersion family, whose discrete densities have no analytic-weight form). Pairing a likelihood oversum(w)units with alog(rows)penalty is what made BIC agree with neither convention.- Type:
float | None
- weight_type
the convention
weightswere read under; seeglm().- Type:
- separated
True when the binomial design separates the classes, so at least one coefficient has no finite maximum-likelihood estimate.
deviance,fittedandlog_likelihoodare still correct (compare nested models by deviance), butcoefandsealong the separating direction record only where IRLS stopped, soz_values/p_valuesrefuse. Announced by aUserWarningat fit time.- Type:
- n_iter
IRLS iterations to convergence.
- Type:
- converged
whether the IRLS convergence criterion was met. Public fits currently raise instead of returning this as false.
- Type:
- rank
effective NUMERICAL rank of the weighted design
sqrt(W) Xat the solution, from the same SVD the covariance is computed from (cutoff atcond(X), notcond(X)^2; audit B4).rank < p– exact or near collinearity – is announced by aUserWarningat fit time and makesz_values/p_valuesrefuse.- Type:
int | None
- family / link
names.
- cov
(p, p)coefficient covariance.- Type:
Call forms:
aic/bicare PROPERTIES (fit.aic, no parentheses) whilez_values/p_valuesare METHODS (fit.z_values()). Both call forms are frozen for compatibility – changing either direction breaks every existing caller – so the split is stated here instead: mixing them up fails withTypeError: 'float' object is not callable(calling the property) or a bound-method object where an array was expected (reading the method), and neither traceback names the actual mistake. All four refuse with a stated reason (no likelihood, rank deficiency, separation, saturation) rather than return NaN.- predict(x, *, offset=None)[source]
Predict the mean response
muat new design rowsx.
- property aic: float
-2 ll + 2 kwithk = rank + estimated dispersion.- Type:
Akaike information criterion
- property bic: float
Bayesian information criterion over the observations the log-likelihood spans.
The penalty has to count the SAME observations the likelihood does (
ll_nobs). Deriving it fromresidual_dfinstead pairs a likelihood summed oversum(weights)replicates with alog(rows)penalty on a frequency table, which is correct under neither weight convention – 107.7 where the two defensible answers were 116.5 and a likelihood of -3.5.
- z_values()[source]
Return Wald statistics for fitted coefficients (full-rank designs only).
- Return type:
- p_values()[source]
Two-sided Wald p-values: Student-t on the residual df when the dispersion was ESTIMATED (Gaussian/Gamma/inverse-Gaussian – the plug-in-dispersion normal reference rejected 9% at nominal 5% at n=8; audit G-1), normal otherwise (fixed-dispersion families), both asymptotic in the non-Gaussian mean model.
- Return type:
- exception PerfectSeparationError[source]
Bases:
RuntimeErrorThe binomial classes are perfectly separated (or perfectly predicted): no finite MLE exists.
Raised by
glm()when IRLS runs the fitted binomial probabilities all the way onto 0 or 1 and can no longer take a step – the terminal form of (quasi-)complete separation, where|coef|diverges and the working weights vanish. A subclass ofRuntimeError, so pre-existing handlers keep working.Separation that stops the iteration just SHORT of that point is the same statistical condition and is reported too, but as a
UserWarningplusGLMResult.separated, because there the fit still carries a correct deviance / fitted / likelihood; only its Wald branch is undefined and refuses. Which of the two a given data set produces is a numerical accident, so never read the absence of this exception as evidence of no separation – readseparated.
- glm(x, y, *, family='gaussian', link=None, offset=None, weights=None, weight_type='analytic', max_iter=100, tol=1e-8, robust=False, theta=1.0)[source]
Fit a generalized linear model by iteratively reweighted least squares.
- Parameters:
x (ndarray) –
(n, p)design matrix (include an intercept column explicitly if wanted).y (ndarray) –
(n,)response (counts, 0/1 or proportions, positive reals, … per the family).family (str | Family) –
"gaussian","binomial","poisson","gamma","inverse_gaussian","negativebinomial", or aFamily.link (str | Link | None) – a link name, or a
Linkinstance to use directly (e.g. a custom link); defaults to the family’s default link (the canonical link, except gamma / inverse-Gaussian which default tolog– their canonicalinverse/inverse_squaredlinks do not keepmupositive).offset (ndarray | None) –
(n,)known additive term on the linear-predictor scale (e.g.logexposure).weights (ndarray | None) –
(n,)non-negative prior weights, at least one positive. Zero-weight rows drop out of the fit entirely. What a weight MEANS is set byweight_type– the two readings agree on the coefficients and on nothing else.weight_type (str) –
the convention
weightsare read under."analytic"(default; also called prior, precision or variance weights – the McCullagh–Nelder reading, and R’s forglm): rowiis ONE observation measured with precisionw_i, soVar(y_i) = phi V(mu_i) / w_i. The sample size is the number of rows:residual_df = rows - rank,dispersiondivides by that, and the log-likelihood is that ofnindependent observations with dispersionsphi/w_i. Where the dispersion is ESTIMATED,phithen absorbs the weights’ scale, so multiplying every weight by a constant leaves the whole fit unchanged – coefficients, standard errors, log-likelihood, AIC and BIC alike – and only the relative precisions matter. (Not so wherephiis fixed at 1: for binomial / Poisson / negative-binomial the weight scale IS the amount of information, and halving every weight widens the standard errors bysqrt(2).) Use this for inverse-variance weighting, measurement precisions or sampling weights; fractional weights are accepted."frequency":w_iis a COUNT – rowistands forw_iidentical observations – so it must be a whole number. Every reported quantity then equals what fitting the expandedsum(w)-row data set gives:residual_df = sum(w) - rank,dispersiondivides by that,robuststandard errors replicate the score, and AIC/BIC spansum(w)observations. Use it for aggregated frequency tables – survey cells, contingency tables, “distinct rows plus a count” extracts.
The gap is not cosmetic. On a 6-row table whose counts sum to 114, the same call gives
se = [0.369, 0.135]analytically and[0.070, 0.025]as frequencies – a factorsqrt((114 - 2) / (6 - 2)) = 5.29– with p-values of 5e-04 against 6e-82. Fixed dispersion families (binomial, Poisson, negative-binomial) return identical coefficients AND standard errors either way, becausephiis never estimated there; onlyresidual_dfand the BIC sample size move. Their likelihood issum w log funder both conventions (a discrete density has no analytic-weight form), soll_nobsissum(w)for them regardless – seeGLMResult.ll_nobs.max_iter (int) – IRLS controls (convergence on the relative deviance change).
tol (float) – IRLS controls (convergence on the relative deviance change).
which coefficient-covariance estimator to report (recorded on the result as
cov_type).False– the default – is the model-basedphi (X'WX)^-1;Trueor"HC0"is the Huber–White sandwich;"HC1"|"HC2"|"HC3"apply the standard finite-sample leverage corrections to the same PSD-by-construction sandwich (MacKinnon–White 1985):HC0: the plain sandwich. No finite-sample correction, so on small or leveraged designs it is biased LOW – measured 16-51% below HC3 on a 12-point design with one leveraged row, i.e. exactly where robust standard errors are reached for. (
robust=Truekeeps meaning HC0 for compatibility.)HC1: HC0 scaled by
n / (n - rank)– the df correction Stata’srobustapplies. Fixes the average small-sample bias but ignores WHERE the leverage sits.HC2: per-observation scores scaled by
1 / sqrt(1 - h_i); exactly unbiased under homoskedasticity. Use when leverage is uneven but n is moderate.HC3: scores scaled by
1 / (1 - h_i)(jackknife-like) – the standard recommendation forn <~ 50or clearly leveraged designs (Long–Ervin 2000); the most conservative of the four.
All four assume INDEPENDENT observations (none is cluster-robust) and still require the mean/link to be correct (audit G-7).
h_iis the observation’s leverage in the converged working weighted regression; underweight_type="frequency"each replicate carries its own leverage, so every estimator equals the expanded data set’s. HC1-3 are refused on a saturated fit (their corrections divide by zero there), and HC2/HC3 on a unit-leverage observation (one fitted by itself alone).theta (float) – the negative-binomial dispersion parameter (
family="negativebinomial"only; ignored otherwise). Not estimated from data – pass the value appropriate to your data (e.g. from a prior fit or a method-of-moments estimate); the default1.0is a plain placeholder, not a fitted value. WARNING (audit G-4): the MODEL-BASED standard errors assumethetais correct – with the placeholder against true theta = 10, measured SEs were 1.87x the true sampling spread (nominal 95% Wald intervals covering ~100%, tests losing essentially all power). Passrobust=Trueunlessthetais trusted, and ifthetacame from the same data, remember AIC/BIC do not count it.
- Returns:
A
GLMResult.- Raises:
PerfectSeparationError – a binomial fit whose fitted probabilities reached exactly 0 or 1, leaving IRLS no finite step. Separation that stalls just short of that returns instead, with
GLMResult.separatedset, aUserWarning, andz_values/p_valuesrefusing – so treatseparated, not the absence of this exception, as the answer to “were my classes separated?” (the exception fires on a continuously coded separation and not on the dummy-coded form of the very same data).- Return type:
GLMResult
- class PenalizedResult(coef, intercept, alpha, l1_ratio, n_iter, converged=True, rank=None)[source]
Bases:
objectFitted penalized linear regression.
- Parameters:
- coef
(p,)coefficients (excluding the intercept).- Type:
- intercept
fitted intercept.
- Type:
- alpha
overall penalty strength.
- Type:
- l1_ratio
elastic-net mixing (1 = lasso, 0 = ridge).
- Type:
- n_iter
coordinate-descent iterations (0 for the closed-form ridge).
- Type:
- ridge_regression(x, y, alpha=1.0, *, fit_intercept=True)[source]
Ridge (L2-penalised) linear regression in closed form.
Minimises
||y - X b||^2 + alpha ||b||^2; the intercept (if fitted) is not penalised.
- elastic_net(x, y, alpha=1.0, l1_ratio=0.5, *, fit_intercept=True, max_iter=1000, tol=1e-7)[source]
Elastic-net linear regression by cyclic coordinate descent.
Minimises
(1/2n) ||y - X b||^2 + alpha ( l1_ratio ||b||_1 + (1 - l1_ratio)/2 ||b||^2 ).l1_ratio = 1is the lasso (sparse);l1_ratio = 0is ridge-shaped, but note the1/(2n)data term meanselastic_net(X, y, a, 0.0)equalsridge_regression(X, y, n*a)– the penalties differ by a factor ofnwhen cross-walking alpha (audit G-5).
- lasso(x, y, alpha=1.0, **kw)[source]
Lasso (L1) linear regression –
elastic_net()withl1_ratio = 1.
- class RegressionFit(coef, fitted, scale, n_iter, converged=True, rank=None, degenerate_scale=False)[source]
Bases:
objectCoefficients + fitted values from
robust_regression()/quantile_regression().- Parameters:
- degenerate_scale
set by
robust_regression()when it detects a sign of its own >50% breakdown point – EITHER the IRLS scale has collapsed (at or within a convergence step of its numerical floor, or far below the raw response’s own spread) with a real share of rows assigned (near) zero weight as a result, OR at least ~44% of the raw response is tied (near enough) to a single value regardless of the fit’s residuals (the shape a capped/censored/zero-inflated measurement produces, which need not collapse the scale at all; see the module comment above_robust_weight_collapsein this file for the full design and, just as importantly, what it still cannot see). Either signal firing means this is not a transient numerical accident, andcoefMAY reflect a majority pattern rather than a fully recovered relationship – but may equally reflect a fit that is completely correct, with the flagged pattern arising because the majority genuinely fits (near-)exactly; seerobust_regression(). This field, and theUserWarningannouncing it at fit time, name the observed CONDITION only, never a verdict: neither can establish whether a real minority signal was discarded or a genuine minority of contamination was correctly rejected (both look identical from this pattern alone), and – a further, structural limitation, not merely an unresolved ambiguity – a majority and minority that follow two genuinely different relationships (as opposed to sharing one tied value) is largely invisible to this mechanism in the first place unless the majority’s own fit is exceptionally tight; see the module comment for exactly how far that reaches and where it stops. AlwaysFalseforquantile_regression(), which has no comparable mechanism.- Type:
- robust_regression(x, y, *, method='huber', c=None, max_iter=100, tol=1e-8)[source]
Robust (M-estimator) linear regression by IRLS with a robust scale.
Down-weights observations with large residuals so a few outliers cannot dominate the fit.
huberuses the Huber weight (tuningc = 1.345for 95% Gaussian efficiency);tukeyuses the redescending Tukey biweight (c = 4.685), which rejects gross outliers entirely.The scale estimate (median absolute residual deviation / 0.6745) is only ever as robust as any MAD-based estimator is: past its own breakdown point – half or more of the rows sharing (near enough) the same residual under the current fit, an ordinary shape for zero-inflated or capped/rounded data and not a contrived one – it is exactly zero by construction and floors at
1e-8(or, as of audit R-3, is treated the same way once it is merely far smaller than the response’s own spread, even without literally reaching that floor). That is an inherent limit of this estimator family, not something iterating further or switchingmethodfixes:tukey’s redescending weight then hard-zeros essentially every row (raised below), andhuber’s never-quite-zero weight instead settles – sometimes only after many iterations – on a near-zero-coefficient fit matching the majority tie that reportsconverged=True. A capped or censored measurement breaks down the same way without ever collapsing the scale estimate itself: a shared ceiling ties rows’ raw responses together but not their residuals once the fit carries any slope, so this is instead read directly off the response (see the module comment above_robust_weight_collapsein this file for the full two-signal detection design, including what audit R-3 closed and what it plainly did not: most notably, a majority and a minority that follow two genuinely DIFFERENT relationships – as opposed to sharing one tied value – is only ever PARTIALLY visible to this mechanism, and a location-only split with no covariate to anchor the response’s own spread is not visible to it at all). All of these are disclosed rather than left looking like an ordinary converged fit: seeRegressionFit.degenerate_scaleand theUserWarningissued at fit time. What is NOT, and cannot be, disclosed: WHICH of “a real minority signal was discarded,” “a minority of contamination was correctly rejected,” or “nothing was discarded at all, because the majority is genuinely this exact” produced a flagged pattern – all three leave the same fingerprint, so the warning names the observed condition, never a verdict on which case it is.A sharper,
method='huber'-specific gap (GAP C in the module comment, campaign nine, D-0209):huber’s weight never fully crushes, so a real minority following a different relationship can be systematically down-weighted enough to biascoeftoward the majority WITHOUT tripping either disclosure signal at all – confirmed common (up to 100% of seeds at a 35% minority fraction, at everyday noise levels), not a rare edge case. Raisingmax_iterpast aRuntimeError("... failed to converge ...")is what usually exposes it: that default failure is a real but incomplete guard, not a guarantee, so a non-convergence error undermethod='huber'is worth treating as a possible sign of exactly this shape rather than simply raisingmax_iterand moving on. Switching tomethod='tukey'is not a reliable workaround for this specific shape either outside a no-intercept design.- Raises:
RuntimeError – every observation lands at zero weight (the message names the breakdown pattern above when one was detected), coefficients become non-finite, or IRLS does not converge in
max_iteriterations.- Parameters:
- Return type:
RegressionFit
- quantile_regression(x, y, tau=0.5, *, max_iter=200, tol=1e-7, eps=1e-6)[source]
Linear quantile regression: the conditional
tau-quantile by IRLS on the check loss.Minimises the pinball loss
sum rho_tau(y - X b)via iteratively reweighted least squares with weightstau / |r|for positive residuals and(1 - tau) / |r|for negative ones (a smoothed Newton scheme;epsfloors|r|for stability).