Limited-dependent-variable and microeconometric workflows for Python.
Project description
limiteddepkit
limiteddepkit is a Python toolkit for limited-dependent-variable and
microeconometric workflows.
It provides a unified, explicit interface for:
- Binary Logit and Probit;
- Firth bias-reduced Binary Logit;
- pooled, generalized, and partial-proportional-odds ordinal models;
- static random-effects Ordered Logit and Probit;
- static fixed-effects Ordered Logit through blow-up-and-cluster estimation;
- dynamic random-effects Ordered Logit with initial-condition controls;
- Poisson and negative-binomial NB2 count models;
- Gaussian censoring, truncation, and interval regression;
- geometric, Exponential, Weibull, and Gamma duration models;
- model-appropriate prediction and post-estimation;
- probability-aware validation and ML-style diagnostics; and
- reproducible comparison and reporting workflows.
The package is intended for applied researchers working with binary choices, ordered outcomes, counts, censored or truncated responses, event durations, and static or dynamic ordinal panels.
The objective is not to collect as many estimators as possible. The objective is to make the observation rule, identification assumptions, prediction target, inferential status, and validation evidence visible enough for replication, review, and applied use.
Alpha warning: the current package version is
0.1.0a2. APIs can change before a stable release. Validation claims are model- and benchmark-specific; they do not imply universal equivalence across datasets, specifications, optimizers, covariance targets, quadrature rules, or software defaults.
Why limiteddepkit?
Limited-outcome analysis often combines an estimator from one library, hand-written category coding, separate marginal-effect calculations, and software-specific reporting. That fragmentation can silently change the estimand or obscure an incompatible data contract.
limiteddepkit is built around six principles.
1. Explicit model specification
Important assumptions remain visible in code:
- binary intercepts are supplied explicitly;
- ordinal designs reject constants because thresholds identify location;
- substantive category order is supplied or retained explicitly;
- censoring and truncation sides are separate observation rules;
- offsets, exposure, weights, and covariance choices are estimator-specific;
- panel entity and time identifiers are passed explicitly; and
- quadrature order and prediction targets are not hidden in reporting helpers.
2. Identification-aware model boundaries
Models that look similar can identify different quantities. The package therefore keeps the following distinctions explicit:
- random effects versus fixed effects;
- static versus dynamic state dependence;
- censoring versus truncation;
- population-average versus conditional versus posterior prediction;
- ordinary maximum likelihood versus Firth or ridge penalization; and
- an econometric estimator versus a prediction challenger.
For example, stable BUC fixed-effects Ordered Logit identifies common slopes but conditions out cutoffs and entity effects. It therefore does not pretend to provide category probabilities or an ordinary ordered-model AIC.
3. Prediction is a first-class estimand
Prediction is not treated as a generic X @ beta afterthought. Depending on the fitted
family, results can expose:
- binary event probabilities;
- one probability per ordered category;
- population-averaged random-effects probabilities;
- probabilities conditional on supplied random effects;
- posterior random-effect summaries and posterior-predictive probabilities;
- expected counts under new offsets or exposure;
- latent, recorded, selection, or censoring targets for Gaussian observation rules; and
- duration means, survival, hazards, cumulative hazards, and quantiles.
These targets are labelled separately because they answer different questions.
4. Unsafe inference remains visible
Results expose converged and inference_valid where applicable. Flexible ordinal models
do not report ordinary Hessian inference when a non-crossing constraint is active.
Experimental fixed-effects Probit requires successful entity-bootstrap inference.
Conditional fixed-effects models do not manufacture unidentified thresholds or
probabilities.
5. Verification is layered
Validation proceeds through:
- API and exact statistical identities;
- aligned comparisons with established Python implementations;
- deterministic simulation recovery and invariance checks;
- explicit guards at identification and optimization boundaries; and
- maintained Stata/R comparison harnesses where an equivalent specification exists.
Controlled certification and real-data application evidence are reported separately.
6. Prediction diagnostics complement econometrics
The experimental limiteddepkit.ml layer adds leakage-aware splitting,
outcome-appropriate scores, calibration, nested model selection, uncertainty-aware
comparisons, censoring-aware duration diagnostics, and optional external-estimator
bridges. It evaluates fitted models; it does not relax identification assumptions or turn
predictive performance into causal or inferential validity.
Current Development Focus
The current development line consolidates the major limited-outcome families behind reviewable contracts.
Recent stable promotions include:
- Gaussian Tobit, truncated regression, and interval regression;
- exposure/offset Poisson and NB2 with explicit weight and covariance semantics;
- geometric, Exponential, Weibull, and Gamma duration models;
- Random-effects Ordered Probit;
- BUC Fixed-effects Ordered Logit; and
- Firth Binary Logit with profile penalized-likelihood confidence intervals.
Two research estimators deliberately remain experimental:
FixedEffectsOrderedProbit, using unconditional entity effects and a split-panel jackknife; andDynamicFixedEffectsOrderedLogit, using the restricted four-outcome-history conditional estimator of Muris, Raposo, and Vandoros.
The separate promoted-family application suite now supplies additional Python/R evidence for these stable additions. That evidence remains distinct from the earlier eight-family controlled certificates and does not turn application agreement into universal equality. The corresponding promoted-family Stata run remains a manual release gate.
Public roadmap, parity, and adoption discussions are part of the development record. See Open development and the GitHub Discussion templates for model-family proposals, validation reports, and use cases.
Quick User Path
Most stable estimators are available from the package root:
import limiteddepkit as ldk
binary = ldk.BinaryLogit().fit(X_binary, y_binary)
ordinal = ldk.OrderedLogit().fit(
X_ordinal,
y_ordinal,
category_order=["low", "medium", "high"],
)
count = ldk.PoissonRegressor().fit(
X_count,
y_count,
exposure=person_time,
cov_type="cluster",
clusters=person_id,
)
censored = ldk.Tobit(censoring_point=0.0, side="left").fit(
X_censored,
y_censored,
covariance_type="robust",
)
print(binary.summary_frame())
print(ordinal.predict_proba(X_ordinal_new))
print(count.predict(X_count_new, exposure=new_person_time))
print(censored.predict(X_censored_new, which="censoring_probability"))
Use pandas DataFrames when possible. Fitted feature names are retained, and prediction DataFrames must reproduce those names and their order.
Focused stable namespaces are also available:
from limiteddepkit.censoring import IntervalRegression, Tobit, TruncatedRegression
from limiteddepkit.count import NegativeBinomialNB2, PoissonRegressor
from limiteddepkit.duration import GammaDuration, GeometricDuration, WeibullDuration
from limiteddepkit.small_sample import FirthBinaryLogit
Installation
Python 3.10 or newer is required. Install the current alpha release from PyPI:
python -m pip install limiteddepkit
For the newest development version, install from a checkout:
git clone https://github.com/Akanom/limiteddepkit.git
cd limiteddepkit
python -m pip install -e .
Or install directly from the repository:
python -m pip install git+https://github.com/Akanom/limiteddepkit.git
Optional dependency groups are separate:
python -m pip install -e ".[plots]" # Matplotlib probability/effect plots
python -m pip install -e ".[validation]" # Statsmodels/scikit-learn reference checks
python -m pip install -e ".[outputhub]" # Universal Output Hub adapter
python -m pip install -e ".[test]" # maintained test environment
python -m pip install -e ".[dev]" # test, lint, build, and release tools
python -m pip install -e ".[neural]" # optional PyTorch prediction challenger
Check the installed version:
import limiteddepkit
print(limiteddepkit.__version__)
Current Feature Coverage
Stable binary and small-sample models
BinaryLogitBinaryProbitFirthBinaryLogit- observed-information inference for ordinary binary MLEs
- profile penalized-likelihood intervals for Firth Logit
- schema-safe probability and class prediction
- binary marginal effects and representative-value margins
- linear combinations and Wald tests where covariance is certified
Stable pooled and flexible ordinal models
OrderedLogitOrderedProbitGeneralizedOrderedLogitPartialProportionalOdds- explicit semantic category order
- threshold-specific slopes
- observed-support non-crossing constraints
- proportional-odds diagnostics
- aligned nested likelihood-ratio comparisons
- category probabilities, predictions, margins, and marginal effects
Stable ordinal panel models
RandomEffectsOrderedLogitRandomEffectsOrderedProbitFixedEffectsOrderedLogitDynamicRandomEffectsOrderedLogit- non-adaptive Gaussian-Hermite quadrature for random-intercept models
- population-average, conditional, and posterior probability targets
- posterior random-effect summaries
- BUC common-slope estimation under unrestricted time-invariant heterogeneity
- lag-category state dependence and explicit initial-condition controls
Stable count models
PoissonRegressorNegativeBinomialNB2NegativeBinomialcompatibility name- additive offsets and positive exposure
- integer frequency weights and analytic estimating-equation weights
- observed-information, HC0, HC1, and cluster covariance
- expected-count prediction with explicit prediction-time exposure
- deviance, Pearson, information, and stationarity diagnostics
Stable censoring and truncation models
- left- or right-censored Gaussian Tobit
- left- or right-truncated Gaussian regression
- exact, finite-interval, left-tail, and right-tail interval regression
- observed-information, robust, and cluster covariance
- latent means and latent predictive intervals
- recorded-response, selection-probability, and censoring-probability targets
Stable duration models
GeometricDurationDiscreteTimeDurationcompatibility nameExponentialDurationWeibullDurationGammaDuration- right-censored single-spell likelihoods
- delayed entry
- integer frequency weights
- observed, robust, and cluster covariance
- mean, survival, hazard, cumulative-hazard, and quantile prediction
Post-estimation and reporting
- labelled result objects
- covariance and confidence intervals
- coefficient summaries
- prediction and probability helpers
- marginal effects and margins where identified
- posterior panel prediction where identified
- ordinal probability and effect plots
- Universal Output Hub conversion for supported ordinal results
Stable workflow layer
- outcome-aware scoring for binary, ordinal, count, continuous, quantile, duration, grouped-choice, and selection outcomes
- iid, stratified, complete-group, entity-holdout, and forward-panel splitters
- cross-validation and validity-gated model comparison
- nested tuning and one-standard-error selection
- calibration and reliability diagnostics
- paired fold and observation/entity bootstrap comparisons
- IPCW survival diagnostics
- lazy Statsmodels, scikit-learn, and generic estimator bridges
- optional residual neural binary challenger
Model Selection Guide
| Research setting | Recommended starting point | Main boundary |
|---|---|---|
| Binary response, finite ordinary MLE | BinaryLogit or BinaryProbit |
Explicit constant; separation is rejected |
| Binary response with separation or small-sample bias concern | FirthBinaryLogit |
Full rank and n > p; not high-dimensional ridge |
| Ordered response with proportional slopes | OrderedLogit or OrderedProbit |
No constant; category order matters |
| Ordered response with non-proportional slopes | PartialProportionalOdds or GeneralizedOrderedLogit |
Inspect non-crossing constraints and inference validity |
| Static ordinal panel with a Gaussian entity intercept | RandomEffectsOrderedLogit or RandomEffectsOrderedProbit |
Distributional random-effects assumption and quadrature sensitivity |
| Static ordinal panel with unrestricted time-invariant heterogeneity | FixedEffectsOrderedLogit |
Common slopes only; no thresholds or probabilities |
| Dynamic ordinal panel with correlated random effects | DynamicRandomEffectsOrderedLogit |
One-step state dependence and explicit initial-condition specification |
| Equidispersed counts | PoissonRegressor |
Conditional Poisson mean/variance specification |
| Quadratically overdispersed counts | NegativeBinomialNB2 |
NB2 variance, not NB1 or a panel count model |
| Boundary-recorded Gaussian response | Tobit |
Censoring keeps boundary observations |
| Sample retained only beyond a boundary | TruncatedRegression |
Truncation removes observations outside support |
| Exact, grouped, or tail-bounded Gaussian response | IntervalRegression |
Homoskedastic Gaussian latent response |
| Integer-period constant hazard | GeometricDuration |
Not a general time-varying baseline hazard |
| Parametric continuous duration | Exponential, Weibull, or Gamma | Right censoring and one record per spell |
Experimental SPJ Probit and MRV dynamic fixed-effects Logit should be chosen only when their narrower panel and identification requirements match the research design.
Quick Start
Binary Logit and Probit
Binary outcomes must be coded exactly as 0 and 1. Add a constant explicitly when the model requires an intercept.
from limiteddepkit import BinaryLogit, BinaryProbit
logit_result = BinaryLogit().fit(X_binary, y_binary)
probit_result = BinaryProbit().fit(X_binary, y_binary)
probabilities = logit_result.predict_proba(X_binary_new)
classes = probit_result.predict(X_binary_new, threshold=0.4)
effects = logit_result.average_marginal_effects(X_binary)
effect_inference = probit_result.average_marginal_effects_inference(X_binary)
Ordinary binary MLEs reject complete or quasi-complete separation rather than returning misleading finite coefficients.
Firth Binary Logit
Use Firth explicitly when the identified low-dimensional specification requires mean-bias reduction or finite estimates under separation.
from limiteddepkit import FirthBinaryLogit
firth_result = FirthBinaryLogit().fit(X_binary, y_binary)
profile_intervals = firth_result.conf_int()
wald_intervals = firth_result.conf_int(method="wald")
profile = firth_result.profile_penalized_loglike(
"treatment",
values=[-1.0, 0.0, 1.0],
)
conf_int() defaults to profile penalized-likelihood intervals. The covariance,
standard errors, z statistics, p-values, and summary_frame() remain labelled
ordinary-Fisher Wald approximations. FLIC/FLAC prediction correction and penalized-
likelihood-ratio p-values are not currently implemented.
Ordered Logit and Probit
Do not include a constant in ordinal X; ordered thresholds identify location.
from limiteddepkit import OrderedLogit, OrderedProbit
order = ["low", "medium", "high"]
ordered_logit = OrderedLogit().fit(
X_ordinal,
y_ordinal,
category_order=order,
)
ordered_probit = OrderedProbit().fit(
X_ordinal,
y_ordinal,
category_order=order,
)
probabilities = ordered_logit.predict_proba(X_ordinal_new)
categories = ordered_probit.predict(X_ordinal_new)
po_test = ordered_logit.proportional_odds_test(X_ordinal, y_ordinal)
Generalized Ordered Logit and Partial Proportional Odds
from limiteddepkit import (
GeneralizedOrderedLogit,
OrderedLogit,
PartialProportionalOdds,
likelihood_ratio_test,
)
generalized = GeneralizedOrderedLogit().fit(
X_ordinal,
y_ordinal,
category_order=order,
)
partial = PartialProportionalOdds(varying=["income"]).fit(
X_ordinal,
y_ordinal,
category_order=order,
)
restricted = OrderedLogit().fit(X_ordinal, y_ordinal, category_order=order)
comparison = likelihood_ratio_test(restricted, partial)
print(generalized.threshold_slopes)
print(generalized.constraint_slack, generalized.inference_valid)
print(comparison.statistic, comparison.p_value, comparison.note)
Prediction raises if new covariates make cumulative indices cross. It does not clip an invalid ordered probability vector. When the non-crossing boundary is active, ordinary Hessian inference is unavailable.
Poisson and NB2 counts
from limiteddepkit import NegativeBinomialNB2, PoissonRegressor
poisson = PoissonRegressor().fit(
X_count,
y_count,
offset=log_baseline_risk,
exposure=person_time,
cov_type="HC1",
)
nb2 = NegativeBinomialNB2().fit(
X_count,
y_count,
exposure=person_time,
cov_type="cluster",
clusters=entity_id,
)
expected_count = nb2.predict(
X_count_new,
exposure=new_person_time,
)
print(nb2.alpha)
print(nb2.diagnostics())
Frequency weights are exact row-replication weights. Analytic weights define estimating equations and therefore do not receive ordinary likelihood AIC/BIC interpretation.
Tobit, truncated regression, and interval regression
from limiteddepkit import IntervalRegression, Tobit, TruncatedRegression
tobit = Tobit(censoring_point=0.0, side="left").fit(
X,
observed_y,
covariance_type="robust",
)
truncated = TruncatedRegression(truncation_point=0.0, side="left").fit(
X_retained,
retained_y,
covariance_type="cluster",
clusters=cluster_id,
)
interval = IntervalRegression().fit(
X,
lower=reported_lower,
upper=reported_upper,
)
recorded_mean = tobit.predict(X_new)
censoring_probability = tobit.predict(X_new, which="censoring_probability")
selection_probability = truncated.predict(X_new, which="selection_probability")
latent_interval = interval.predict_latent_interval(X_new, level=0.95)
Censoring and truncation are different likelihoods. Robust covariance changes inference; it does not repair a misspecified Gaussian latent distribution or observation rule.
Duration models
from limiteddepkit import WeibullDuration
duration_result = WeibullDuration().fit(
X_duration,
duration,
event,
entry=entry_time,
frequency_weights=frequency,
covariance_type="cluster",
clusters=entity_id,
)
mean_duration = duration_result.predict_mean(X_duration_new)
survival = duration_result.predict_survival(X_duration_new, times=[1.0, 3.0, 5.0])
hazard = duration_result.predict_hazard(X_duration_new, times=[1.0, 3.0, 5.0])
median = duration_result.predict_quantile(X_duration_new, probability=0.5)
The stable duration family is parametric, right-censored, and single-record-per-spell. It does not claim recurrent-event, competing-risk, frailty, interval-censoring, or time-varying-covariate support.
Ordinal Panel Models
Random-effects Ordered Logit and Probit
The static random-intercept models use
Pr(y_it <= j | x_it, u_i) = F(kappa_j - x_it' beta - u_i),
u_i ~ Normal(0, sigma_entity^2).
F is logistic for RandomEffectsOrderedLogit and standard normal for
RandomEffectsOrderedProbit. Both use non-adaptive Gaussian-Hermite quadrature in log
space.
from limiteddepkit import RandomEffectsOrderedLogit, RandomEffectsOrderedProbit
re_logit = RandomEffectsOrderedLogit().fit(
X_panel,
y_panel,
entity=entity_id,
category_order=order,
quadrature_points=12,
)
re_probit = RandomEffectsOrderedProbit().fit(
X_panel,
y_panel,
entity=entity_id,
category_order=order,
quadrature_points=12,
)
population_average = re_logit.predict_proba(X_panel_new)
conditional_at_zero = re_logit.predict_proba(X_panel_new, random_effects=0.0)
posterior = re_logit.posterior_random_effects(
X_panel,
y_panel,
entity=entity_id,
)
posterior_prediction = re_logit.posterior_predict_proba(
X_panel_new,
entity=new_entity_id,
posterior=posterior,
)
The posterior SD describes uncertainty in an entity effect conditional on fitted model parameters. It is not a frequentist parameter standard error. Refit important models with more quadrature points and inspect coefficient, variance, likelihood, and probability sensitivity.
BUC Fixed-effects Ordered Logit
FixedEffectsOrderedLogit implements the blow-up-and-cluster estimator. It dichotomizes
the response at each cutoff, conditions each binary clone on its entity success count,
sums the conditional log likelihoods, and clusters the composite covariance by entity.
from limiteddepkit import FixedEffectsOrderedLogit
fe_logit = FixedEffectsOrderedLogit().fit(
X_panel,
y_panel,
entity=entity_id,
category_order=order,
)
print(fe_logit.params)
print(fe_logit.odds_ratios())
print(fe_logit.linear_index(X_panel_new))
BUC identifies common slopes. It does not identify cutoffs, entity effects, category probabilities, marginal effects, or an ordinary ordered-model likelihood/AIC.
Dynamic random-effects Ordered Logit
The stable dynamic random-effects model adds lag-category indicators, initial-outcome indicators, initial-period covariates, post-initial entity means, and a remaining Gaussian entity intercept.
from limiteddepkit import DynamicRandomEffectsOrderedLogit
dynamic = DynamicRandomEffectsOrderedLogit().fit(
X_dynamic,
y_dynamic,
entity=entity_id,
time=period,
category_order=order,
quadrature_points=12,
)
print(dynamic.structural_params)
print(dynamic.state_dependence_params)
print(dynamic.initial_condition_params)
print(dynamic.correlated_effects_params)
one_step = dynamic.predict_proba(
X_dynamic_new,
entity=new_entity_id,
lagged_y=lagged_category,
)
Only the initial contiguous spell for each entity enters the likelihood. A time gap does not silently start a new spell. One-step prediction requires an explicit lagged category; multi-step propagation of the complete predicted category distribution is not currently exposed.
State-dependence coefficients are category-relative latent-index shifts, not a scalar autoregressive coefficient and not automatically causal effects.
Experimental Research Estimators
Experimental estimators are importable from limiteddepkit.experimental. Their APIs and
inferential contracts can change before promotion.
SPJ Fixed-effects Ordered Probit
There is no Ordered-Probit equivalent of the Logit conditional likelihood. The experimental estimator fits unconditional entity-effects Ordered Probit to the full panel and two time halves, then applies
2 * full_panel - (first_half + second_half) / 2
to common slopes and thresholds.
from limiteddepkit.experimental import FixedEffectsOrderedProbit
fe_probit = FixedEffectsOrderedProbit().fit(
X_panel,
y_panel,
entity=entity_id,
time=period,
category_order=order,
bootstrap_repetitions=200,
random_state=2026,
)
The current contract requires a balanced common time grid, even T >= 6, category
support in both halves, finite nuisance effects, and successful entity-bootstrap
inference. Six periods is a computational guardrail, not a general claim that the
large-T approximation is reliable. Known-entity probabilities combine corrected common
parameters with uncorrected nuisance effects and are diagnostic only.
MRV Dynamic Fixed-effects Ordered Logit
DynamicFixedEffectsOrderedLogit implements a narrow fixed-T conditional estimator,
not an ordered dummy-variable likelihood and not static BUC with a lag appended.
from limiteddepkit.experimental import DynamicFixedEffectsOrderedLogit
dynamic_fe = DynamicFixedEffectsOrderedLogit().fit(
X_dynamic_fe,
y_dynamic_fe,
entity=entity_id,
time=period,
state_cutoff="good",
category_order=["poor", "fair", "good", "excellent"],
)
print(dynamic_fe.params)
print(dynamic_fe.state_dependence)
print(dynamic_fe.thresholds)
print(dynamic_fe.conditional_sample_frame())
The implementation requires exactly four consecutive outcome observations per entity, discrete exact stayers, a known state cutoff, restricted state dependence, and sufficient conditional-history variation. Fixed effects are conditioned out. Category probabilities, entity effects, marginal effects, ordinary AIC/BIC, and multi-step forecasts are not available.
Its Statsmodels comparison validates optimization and sandwich assembly after the same conditional pseudo-sample has been constructed. It is not an independent replication of the MRV history construction, and no Stata/R parity certificate is claimed.
Other provisional families
- ridge Binary and Ordered Logit;
- Multinomial, Conditional, and Sequential Logit;
- zero-inflated and hurdle Poisson;
- Gaussian sample selection; and
- fixed-boundary censored quantile regression.
See Experimental model status for current evidence and remaining promotion gates.
Data and Identification Conventions
Binary models
ymust be one-dimensional, contain both classes, and be coded exactly 0/1.- Add an explicit constant column when an intercept is required.
- Ordinary MLE models reject separation; Firth is an explicit alternative.
- Firth and ridge require full rank and
n > p; they are not high-dimensional methods.
Ordinal models
- Do not include a constant in
X. - Supply
category_order=for substantive labels unlessyis an ordered pandas categorical. - Every declared category must be observed.
- Save category maps because reversing the order changes the model.
Panel models
- Entity labels must be non-missing but need not be numeric.
- Dynamic time must be numeric with unique entity-time pairs.
- Static random-effects models support unbalanced groups.
- BUC uses within-entity information and rejects time-invariant or collinear regressors.
- SPJ Probit requires a balanced common time grid.
- MRV dynamic fixed effects requires its exact four-observation design.
Shared design rules
- Native estimators accept dense finite numeric arrays or DataFrames.
- DataFrame feature names must be unique.
- Prediction DataFrames must match fitted columns and order.
- Formula parsing and automatic categorical encoding are not part of
0.1.0a2. - Weight, covariance, offset, exposure, and cluster support are family-specific.
- The package does not silently impute missing values or rebuild a preprocessing pipeline.
See Category ordering and the individual model guides for the complete input contracts.
Results and Post-Estimation
Supported result objects expose a model-appropriate subset of:
paramsandall_params;standard_errors,zstats, andpvalues;covariance,vcov(), andconf_int();loglike,aic, andbicwhere meaningful;converged,inference_valid, and score diagnostics;summary_frame();predict()andpredict_proba(); and- family-specific effect, posterior, distribution, or survival methods.
Check converged and inference_valid before interpreting a coefficient table. A result
can contain useful point estimates while ordinary normal-approximation inference is
unavailable.
Function-style facade
from limiteddepkit import (
confint,
lincom,
marginal_effects,
margins,
predict,
predict_proba,
summary_frame,
vcov,
wald_test,
)
table = summary_frame(ordered_logit)
covariance = vcov(ordered_logit)
intervals = confint(ordered_logit)
probabilities = predict_proba(ordered_logit, X_ordinal_new)
labels = predict(ordered_logit, X_ordinal_new)
effects = marginal_effects(ordered_logit, X_ordinal)
average = margins(ordered_logit, X_ordinal, at="overall")
difference = lincom(ordered_logit, {"income": 1.0, "age": -1.0})
joint = wald_test(ordered_logit, [{"income": 1.0}, {"age": 1.0}])
Helpers reject unknown parameter names and inherit the fitted covariance's validity.
Prediction Targets
| Family | Main prediction target | Important distinction |
|---|---|---|
| Binary/Firth | Pr(y=0) and Pr(y=1) |
Firth plug-in probabilities are not FLIC/FLAC calibration |
| Pooled/flexible ordinal | One probability per category | Effects are category-specific |
| Static RE ordinal | Population average by default | Conditional and posterior targets are separate |
| BUC FE Ordered Logit | Common index X beta only |
Thresholds and probabilities are not identified |
| Dynamic RE ordinal | One-step population-average probabilities | Explicit lagged category is required |
| Count | Expected count | New offset/exposure must be supplied explicitly |
| Tobit | Mean recorded response by default | Latent mean and censoring probability are separate |
| Truncated regression | Mean conditional on selection | Latent mean and selection probability are separate |
| Interval regression | Latent mean | Predictive intervals are for future latent outcomes |
| Duration | Mean, survival, hazard, cumulative hazard, quantile | Time grids and spell assumptions must be reported |
For random effects, do not interchange:
- population-average prediction;
- conditional prediction at
u = 0or another supplied effect; - posterior-mean plug-in prediction; and
- exact posterior-predictive integration.
Plotting and Reporting
Pooled and flexible ordinal results support probability and marginal-effect plots when
the [plots] extra is installed:
from limiteddepkit import plot_marginal_effects, plot_probabilities
ax1 = plot_probabilities(ordered_logit, X_ordinal, feature="income")
ax2 = plot_marginal_effects(ordered_logit, X_ordinal, feature="income")
Other covariates are held at their means. These helpers do not currently cover binary or panel results.
Supported ordinal results can be adapted to universal-output-hub:
from limiteddepkit import add_to_outputhub, to_outputhub_model
from universal_output_hub import OutputHub
model = to_outputhub_model(
ordered_logit,
name="Ordered rating",
depvar="rating",
)
hub = OutputHub("Ordinal analysis")
add_to_outputhub(
hub,
ordered_logit,
name="Ordered rating",
X=X_ordinal,
)
Supplying X adds delta-method average-marginal-effect inference for supported pooled or
flexible ordinal models. Panel models can be exported as coefficient models but do not
receive a pooled AME table.
Probability-Aware ML and Diagnostic Layer
limiteddepkit.ml is stable and dependency-light. It operates around fitted
econometric models without changing their likelihoods or identification assumptions.
Outcome-aware scores
| Outcome | Available diagnostics |
|---|---|
| Binary | log loss, Brier score, ROC AUC, accuracy, balanced accuracy |
| Multinomial | multiclass log loss and Brier score |
| Ordinal | multiclass scores, Ranked Probability Score, ordered-category MAE |
| Grouped choice | choice-set log loss, Brier score, hit rate |
| Continuous/censored mean | MAE, RMSE, prediction bias |
| Count | MAE, RMSE, Poisson deviance, zero-rate calibration |
| Quantile | check loss |
| Duration | concordance, IPCW Brier curves, integrated Brier, dynamic AUC |
| Selection | selection scores plus selected-outcome RMSE |
Probability scores are primary for categorical models. Accuracy is a secondary description, not a replacement for calibration or proper scoring rules.
Leakage-aware splitting and comparison
from limiteddepkit import GeneralizedOrderedLogit, OrderedLogit
from limiteddepkit.ml import StratifiedKFold, compare_models
comparison = compare_models(
{
"ordered_logit": OrderedLogit,
"generalized": GeneralizedOrderedLogit,
},
X_ordinal,
y_ordinal,
splitter=StratifiedKFold(
n_splits=5,
shuffle=True,
random_state=2026,
),
outcome="ordinal",
)
print(comparison.table)
print(comparison.best_model)
Available split designs include independent K-fold, stratified K-fold, complete-group holdout, entity holdout, stratified group splitting, repeated designs, and forward panel windows. Compared models reuse the same materialized folds. Fold-local preprocessing must be supplied as a factory so each transformer is fitted only on training rows.
Models are ranked only when configured econometric gates pass. Non-convergence, invalid inference, non-crossing failure, or non-finite primary scores remain visible and can exclude a candidate from automatic ranking.
Nested tuning and uncertainty-aware comparison
The layer supports nested cross-validation, the one-standard-error rule, paired fold differences, and observation- or entity-bootstrap intervals. Ridge strengths and neural hyperparameters should be selected inside the inner loop, never on the outer test folds.
Optional residual neural challenger
ResidualBinaryMLP is a prediction challenger, not an econometric estimator.
from limiteddepkit.ml import ResidualBinaryMLP, StratifiedKFold, cross_validate
neural_cv = cross_validate(
lambda: ResidualBinaryMLP(
hidden_width=32,
n_blocks=2,
dropout=0.15,
weight_decay=1e-3,
patience=30,
temperature_scaling=True,
random_state=2026,
),
X_binary,
y_binary,
splitter=StratifiedKFold(5, shuffle=True, random_state=90210),
outcome="binary",
require_inference_valid=False,
)
The model uses residual GELU/LayerNorm blocks, AdamW, gradient clipping, train-only
standardization, early stopping, optional temperature scaling, and Monte Carlo dropout.
Its result intentionally reports inference_valid=False. The current internal validation
split is iid-stratified; grouped and chronological neural validation are not claimed.
See Probability-aware validation workflows for splitter, alignment, calibration, survival, and uncertainty contracts.
Verification Philosophy
Verification is a core design principle of limiteddepkit.
Where equivalent estimands exist, maintained tests compare with established Python, R, and Stata implementations. Where no equivalent external estimator exists, the package uses exact likelihood identities, independent kernels, deterministic recovery, invariance checks, and explicit refusal tests.
The purpose is not to label every numerical check “parity.” The purpose is to state what was compared, under which specification, and what remains unverified.
Current Validation Status
| Component | Status | Evidence boundary |
|---|---|---|
| Binary Logit/Probit | Maintained Python reference gate | Statsmodels coefficients, likelihood, covariance, probabilities, criteria, AMEs |
| Firth Binary Logit | Maintained Python reference gate; separate R application pass | Exact separated table, firthmodels profile checks, and independent R adjusted-score replication |
| Ordered Logit/Probit | Maintained Python reference gate | Aligned Statsmodels OrderedModel specifications |
| Generalized/PPO Logit | Maintained recovery and constraint gates | Known bounded-support DGPs and non-crossing behavior |
| Static RE Ordered Logit | Maintained recovery/numerical gate; included in prior Stata/R certificates | Quadrature, invariance, posterior identities, aligned certified benchmark |
| Static RE Ordered Probit | Maintained Python identity/recovery gate; separate R application pass | Conditional kernel, normal-convolution identity, and aligned ordinal::clmm application |
| BUC FE Ordered Logit | Maintained conditional-likelihood Python gate; separate R application pass | Exact enumeration, Statsmodels construction, and R survival::clogit likelihood identity |
| Dynamic RE Ordered Logit | Maintained recovery/numerical gate; included in prior Stata/R certificates | Exact specification, quadrature, invariance, initial/gap rules |
| Poisson/NB2 | Maintained Statsmodels gate; separate R application pass | Coefficients, likelihood, dispersion, offsets/exposure, weights, covariance, and R package replication |
| Gaussian censoring family | Maintained identity/Statsmodels gate; separate R application pass | Likelihood identities, reflections, OLS submodel, robust covariance, and aligned R applications |
| Duration family | Maintained Statsmodels/SciPy/identity gate; separate R application pass | Poisson-exposure, distribution contributions, entry, weights, covariance, tails, and aligned R applications |
| SPJ FE Ordered Probit | Experimental Python reference/recovery gate | Uncorrected dummy likelihood, jackknife identity, bootstrap path; no Stata/R certificate |
| MRV dynamic FE Ordered Logit | Experimental conditional-sample Python gate | Path odds, recovery, Statsmodels pseudo-sample optimization/covariance; no independent construction parity |
| ML metrics and ordinary splitters | Maintained scikit-learn comparison gate | Directly equivalent definitions plus documented intentional differences |
| Residual neural challenger | Maintained optional runtime/contract gate | Training/calibration/MC-dropout tests; no numerical-parity or inference claim |
Newer promotions are not automatically covered by older certificates. Read each family guide and Validation strategy for the exact claim boundary.
Eight-Family Stata and R Certificates
The pre-expansion binary/ordinal surface has four completed external-software tracks.
The eight models are:
- Binary Logit;
- Binary Probit;
- Ordered Logit;
- Ordered Probit;
- Generalized Ordered Logit;
- Partial Proportional Odds;
- static Random-effects Ordered Logit; and
- dynamic Random-effects Ordered Logit.
| Track | Purpose | Recorded result |
|---|---|---|
| Controlled synthetic — Stata 17 | Strict benchmark-specific certification | PASS — 82/82 |
| Frozen public-data application — Stata 17 | Applied data-handling check | PASS — 82/82 |
| Controlled synthetic — pinned R 4.5.1 | Independent implementation check | PASS — 110/110 |
| Frozen public-data application — pinned R 4.5.1 | Applied check on the same observations | PASS — 110/110 |
The controlled track is the certification benchmark. The real-data track is an
application check and does not broaden the certification claim. The comparisons were
completed on 14 July 2026; Stata used gologit2 3.2.8, and R used aligned glm.fit,
MASS::polr, VGAM::vglm, and ordinal::clmm specifications.
Observed maximum absolute differences across the completed reports were:
| Track | Implementation | Estimate | Standard error | Covariance | Log likelihood | Probability |
|---|---|---|---|---|---|---|
| Controlled | Stata | 4.16e-6 |
3.03e-7 |
2.14e-7 |
3.53e-9 |
1.56e-6 |
| Controlled | R | 1.02e-5 |
1.26e-5 |
3.85e-6 |
1.53e-4 |
3.07e-6 |
| Real data | Stata | 1.47e-5 |
2.11e-6 |
2.36e-6 |
2.58e-9 |
2.77e-6 |
| Real data | R | 3.19e-4 |
2.05e-4 |
2.29e-4 |
5.35e-4 |
5.05e-5 |
These values are inside their declared model-family gates; they are not universal tolerances for future analyses.
The certificates do not cover Firth, censoring, counts, duration, Random-effects Ordered Probit, BUC Fixed-effects Ordered Logit, SPJ Fixed-effects Ordered Probit, or MRV Dynamic Fixed-effects Ordered Logit. A separate application suite now adds external Python/R evidence for the stable promoted families; it is not an extension of the controlled certificate. The two experimental fixed-effects estimators retain only their model-specific Python/reference evidence summarized above.
See the evidence index, Stata harness, and R harness for hashes, mappings, tolerances, commands, and allowed claim language.
Promoted-Family Python/R Application Evidence
The stable families added after the original eight-model surface have a separate public-data application harness. On 15 July 2026, all 12 Python and R fits completed and all 120/120 registered comparisons passed their model-specific gates.
The evidence comprises:
- seven comparisons with industrial R packages;
- three independent likelihood or adjusted-score implementations; and
- two exact likelihood or pseudo-sample identities.
These labels are deliberate: identity and independently coded likelihood checks are
useful replication evidence, but they are not package-to-package agreement. The
applications use empirical LBW, infant-mortality, labor-supply, cancer-duration,
TVSFPORS, and NLSWORK observations. The interval-regression check instead uses the
official fictional womenwage2 software fixture because it exercises native open
endpoints; it must not be described as empirical data.
The corresponding manual Stata application run also passed its required checks:
140/140, with one explicit skip for Gamma duration because Stata's generalized
Gamma is not the same ordinary Gamma likelihood. Firth Binary Logit ran through
optional firthlogit and passed its aligned Stata checks. This result is application evidence only.
It neither extends the older controlled certification nor claims universal
numerical equality across datasets, specifications, optimizers, covariance
estimands, or software versions.
See the promoted-family application harness and cross-software evidence index for the model map, provenance, commands, tolerances, recorded hashes, and allowed claim language.
Practical Modelling Guidance
Start with the simplest defensible specification
A useful ordinal progression is:
- pooled Ordered Logit or Probit;
- inspect category order and the proportional-odds restriction;
- relax named slopes with Partial Proportional Odds;
- use Generalized Ordered Logit only when the broader flexibility is justified;
- add random effects or fixed effects only when the panel estimand is required; and
- introduce dynamic state dependence only with an explicit initial-condition strategy.
Keep observation rules separate
- Use Tobit when observations remain at a censoring boundary.
- Use truncated regression when observations outside support are absent.
- Use interval regression for exact, grouped, or open-tail bounds.
- Use duration likelihoods for event-time processes, not merely because a continuous response is positive.
Name the prediction target
Report whether predictions are population averaged, conditional on a supplied random effect, posterior-mean plug-ins, exact posterior predictive, latent, recorded, selected, or survival-scale quantities.
Treat dynamic state dependence cautiously
Lagged outcome association can reflect genuine state dependence, unobserved heterogeneity, initial conditions, or specification error. A fitted state coefficient is not automatic causal evidence.
Preserve the preprocessing design
Save category maps, dummy levels, interactions, scales, feature order, offsets, exposure, entry times, and sample filters. The package does not store a formula or preprocessing pipeline for later reconstruction.
Recommended Reporting
For publication or review, report:
- exact package version and estimator class;
- outcome coding and ordinal category order;
- sample construction, exclusions, and missing-data handling;
- design columns and transformation rules;
- explicit binary intercept choice or confirmation that ordinal
Xhas no constant; - observations, entities/clusters, effective weighted observations, and contributing conditional groups where relevant;
- optimizer controls, convergence, score diagnostics, and
inference_valid; - covariance type, finite-sample correction, confidence level, and bootstrap details;
- coefficient, threshold, dispersion, scale, shape, or random-effect parameterization;
- offset, exposure, weight, censoring, truncation, delayed-entry, or duration convention;
- quadrature method and point count for random-effects models;
- prediction target and whether random effects are integrated, supplied, or posterior;
- dynamic time-step, initial-condition controls, lag-category specification, and rows removed after gaps;
- BUC/SPJ/MRV identification limitations when those estimators are used; and
- exact external-software track, versions, mappings, data manifest, and tolerance when a parity statement is reported.
Archive the manifest, prepared data or permitted provenance, Python references, Stata/R exports, logs, comparator reports, software versions, and certificates with any external parity claim.
Package Scope
limiteddepkit contains models whose response, observation rule, duration, or choice
mechanism is intrinsically limited. It is not a general home for every econometric model.
The following were deliberately kept outside the installed package:
- ordinary linear IV/treatment-effect 2SLS;
- iid Gaussian mixtures and generic switching regression;
- ordinary uncensored quantile regression; and
- a generic generalized additive model.
The historical 2SLS and mixture sources are retained under _out_of_scope/ for possible
migration to causal/IV and regime-model packages. Future nonlinear basis support should
serve an in-scope outcome family rather than create a generic GAM label without a
limited-response estimand.
See Package scope for the complete keep/extract rationale.
Roadmap
Near-term work remains evidence-driven:
- archive completed external-software evidence with an exact repository revision;
- rerun Stata/R tracks after estimator, mapping, or reference changes;
- add independent replication for newly promoted panel families where equivalent software exists;
- strengthen SPJ Probit recovery and bootstrap evidence on longer panels;
- independently replicate the MRV conditional-history construction before considering promotion;
- broaden weight, covariance, exposure, entry, and prediction contracts only with an explicit estimand and maintained tests;
- improve reporting around model-specific convergence and identification diagnostics; and
- preserve the stable/experimental boundary instead of expanding the root merely to increase model count.
No experimental estimator has a promised promotion date.
Documentation
Start with the documentation index.
Model guides:
- Binary models
- Small-sample binary models
- Ordinal models
- Category ordering
- Panel ordinal models
- Fixed-effects ordinal panels
- Dynamic random-effects ordinal models
- Dynamic fixed-effects Ordered Logit
- Gaussian censoring models
- Count models
- Duration models
Workflow and evidence guides:
- Probability-aware validation and ML workflows
- Validation strategy
- Experimental model status
- Ecosystem compatibility
- Dynamic ordinal numerical validation
- Cross-software evidence index
- Stata parity harness
- R parity harness
- Promoted-family application harness
Project processes:
Citation
If you use limiteddepkit, cite the software and the exact version used.
Machine-readable metadata is available in CITATION.cff.
Suggested interim citation:
Akanbi, Oluwajuwon Mayomi.
limiteddepkit: Limited-dependent-variable models for Python.
Version 0.1.0a2, 2026.
No DOI or archival identifier is asserted before one is assigned. Add the permanent identifier when a public archive exists.
License
MIT License.
See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file limiteddepkit-0.1.0a2.tar.gz.
File metadata
- Download URL: limiteddepkit-0.1.0a2.tar.gz
- Upload date:
- Size: 462.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c5d5c7a0766de9fd4cff236346200cbc729485c6b4d429c10ed188d9be3b3c5
|
|
| MD5 |
23b94bb392cf2a7d01f455822a60b857
|
|
| BLAKE2b-256 |
58bca1bf90af87ae9f6224adcc2e717fce3328fdaaddfb3785c69c0b11f7b1df
|
Provenance
The following attestation bundles were made for limiteddepkit-0.1.0a2.tar.gz:
Publisher:
publish.yml on Akanom/limiteddepkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
limiteddepkit-0.1.0a2.tar.gz -
Subject digest:
9c5d5c7a0766de9fd4cff236346200cbc729485c6b4d429c10ed188d9be3b3c5 - Sigstore transparency entry: 2216265651
- Sigstore integration time:
-
Permalink:
Akanom/limiteddepkit@6a27c5d6f2180f1a6b83a74a4132b8057084cae7 -
Branch / Tag:
refs/tags/v0.1.0a2 - Owner: https://github.com/Akanom
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6a27c5d6f2180f1a6b83a74a4132b8057084cae7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file limiteddepkit-0.1.0a2-py3-none-any.whl.
File metadata
- Download URL: limiteddepkit-0.1.0a2-py3-none-any.whl
- Upload date:
- Size: 225.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86c65e69548c9bda9f34f7886dade17a0288f2b8ce442797e717645181dd8f90
|
|
| MD5 |
9c29cc8522fdeb7c0c67c724ad9f846c
|
|
| BLAKE2b-256 |
6316a83afe1143469b8b0ae6cd0d13ad2418a057e79f3fde5014665ba8e23b24
|
Provenance
The following attestation bundles were made for limiteddepkit-0.1.0a2-py3-none-any.whl:
Publisher:
publish.yml on Akanom/limiteddepkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
limiteddepkit-0.1.0a2-py3-none-any.whl -
Subject digest:
86c65e69548c9bda9f34f7886dade17a0288f2b8ce442797e717645181dd8f90 - Sigstore transparency entry: 2216265675
- Sigstore integration time:
-
Permalink:
Akanom/limiteddepkit@6a27c5d6f2180f1a6b83a74a4132b8057084cae7 -
Branch / Tag:
refs/tags/v0.1.0a2 - Owner: https://github.com/Akanom
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6a27c5d6f2180f1a6b83a74a4132b8057084cae7 -
Trigger Event:
release
-
Statement type: