Release 0.15.0#

Release summary#

This note covers all changes merged into main between the v0.15.0.dev0 tag (2023-05-05) and the current development head (2026-07-22). It is a working draft assembled directly from the git history rather than a final, polished release announcement, and it does not yet follow the format of previous versionX.Y.rst release notes.

statsmodels is using github to store the updated documentation. Two versions are available:

Warning

API stability is not guaranteed for new features, although even in this case changes will be made in a backwards compatible way if possible. The stability of a new feature depends on how much time it was already in statsmodels main and how much usage it has already seen. If there are specific known problems or limitations, then they are mentioned in the docstrings.

Release statistics#

  • Pull requests merged: 355

  • Non-merge commits: 953

  • Contributors (by git log author, unique names): 122

  • Time span: 2023-05-05 through 2026-07-22

The Highlights#

SPEC-007: consistent use of rng for randomness#

statsmodels is standardizing on a single rng keyword for supplying entropy (an integer seed, an array of integers, a NumPy Generator, or a RandomState) wherever a model, estimator, or plotting function needs randomness, in line with the community’s SPEC 007 convention. The older random_state and seed keywords are deprecated in favor of rng. Passing the old keyword still works and is transparently remapped to rng, but it now raises a FutureWarning and will be removed in a future release. This is one of the largest cross-cutting changes in this release and touches, among others:

  • State space models (MLEResults.simulate, simulation smoothers, impulse response simulation): random_state -> rng.

  • Distributions: copulas, BernsteinDistribution, DiscretizedCount, MixtureDistribution, and related rvs-style methods: random_state -> rng.

  • MixedLM, nonlinls, GAM cross-validation, and several sandbox distributions: random_state -> rng.

  • Nonparametric estimation (KDEMultivariate, KDEMultivariateConditional, KernelReg, KernelCensoredReg, TestRegCoefC/TestRegCoefD): seed -> rng.

  • VAR/SVAR/IRF simulation and Monte Carlo error bands (varsim, VAR.simulate_var, VAR.plotsim, VARResults.irf_errband_mc, VARResults.irf_resim, SVARResults.sirf_errband_mc, and the IRAnalysis.plot/plot_cum_effects/errband_mc/err_band_sz1/ err_band_sz2/err_band_sz3/cum_errband_mc family): seed -> rng.

  • ARDL.bounds_test, graphics.functional.hdrboxplot (seed and kernel_seed), and sandbox.panel.random_panel.PanelSample: seed -> rng.

  • The internal statsmodels.tools.rng_qrng.check_random_state helper (which also accepts scipy.stats.qmc.QMCEngine instances) is now used consistently across these code paths to turn whatever is passed via rng into an actual Generator/RandomState instance.

See Breaking Changes and Deprecations below for what this means for existing code. PR #9737, PR #9615, PR #9831, PR #9947, PR #9950

Formula engine: patsy is no longer the only option#

statsmodels now has an abstracted formula-handling layer (statsmodels.formula) that can use either patsy (the default engine when it is installed, for backward compatibility) or formulaic as the engine behind the formula interface (smf.ols("y ~ x", data=df), etc.). The engine can be selected explicitly with the SM_FORMULA_ENGINE environment variable ("patsy" or "formulaic"). formulaic is now a required runtime dependency (formulaic>=1.1.0) even when patsy continues to be used as the default engine. This lays the groundwork for statsmodels to move away from patsy, which has been in low-maintenance mode for several years. PR #9423, PR #9470

Build system: meson-python replaces setuptools#

statsmodels’ build backend switched from setuptools (with a custom setup.py) to meson-python. Anyone building statsmodels from source needs Meson/Ninja available and a build environment satisfying the new build requirements (numpy>=2.0, scipy>=1.13, cython>=3.0.13). This does not affect users installing prebuilt wheels from PyPI. PR #9634

New robust estimation tools#

Several new robust estimators and supporting tools were added:

  • statsmodels.robust.covariance.CovDetMCD (minimum covariance determinant with deterministic starts), CovDetS (S-estimator for mean/covariance with deterministic starts), and CovDetMM (an MM-estimator built on top of CovDetS). These are preliminary/experimental APIs. PR #9227, PR #8129

  • statsmodels.robust.resistant_linear_model.RLMDetSMM, an MM-estimator for regression using S-estimator starting values, plus additional robust norms and supporting tools. PR #9186

  • Fixes and additions to scale.Huber and a new robust M-scale estimator. PR #9210

New models and statistical tests#

  • statsmodels.multivariate.multivariate_ols.MultivariateLS, a new multivariate least-squares model. PR #8919

  • statsmodels.tsa.stattools.leybourne implementing the Leybourne-McCabe stationarity test. PR #9399

  • A two-sample z-test for the unequal-variances case. PR #8959

  • "one-sided" alternative hypotheses for proportion_confint and confint_poisson. PR #9249, PR #9255

  • Games-Howell post-hoc test added alongside a fix to Tukey’s HSD for the unequal-variance case. PR #9487

  • A sample-size calculation for the Wilcoxon/Mann-Whitney test. PR #9401

  • Order validation for the Hannan-Rissanen ARMA estimator. PR #9819

  • ARDL models can now use a "ctt" trend. PR #9518

  • x13_arima_analysis gained seasonality fit diagnostics and an optional raw spec parameter. PR #9498, PR #9550

New and improved plots#

  • statsmodels.graphics.tsaplots.plot_ccf and plot_accf_grid for plotting cross-correlations and cross-correlation matrices, and ccf gained an option to return confidence intervals. PR #8782, PR #8783

  • statsmodels.graphics.tsaplots.seasonal_diagnostic_plot, a new seasonal diagnostic plot. PR #9787

  • statsmodels.graphics.regressionplots.add_ellipse for adding confidence ellipses to scatter plots. PR #9815

  • qqplot_2samples accepts additional plot keyword arguments. PR #9544

GLM and other model enhancements#

  • GLMResults.get_margeff (marginal effects for GLM). PR #8889

  • GLM models now preserve the names of input pandas Series. PR #9130

  • het_white gained an option to omit interaction (cross) terms. PR #9691

  • Faster computation of state space “news”/revision impacts, and a significant performance optimization of VECM to avoid an \(O(T^2)\) projection matrix. PR #8937, PR #9720

Platform and packaging compatibility#

  • Cython 3 compatibility, and compatibility of the tsa.statespace Cython code with SciPy ILP64 builds. PR #9078, PR #9798

  • Experimental Pyodide/WebAssembly support and CI jobs. PR #9270, PR #9343

  • Free-threaded (no-GIL) CPython compatibility work, including free-threading-compatible Cython modules and CI coverage. PR #9717

Notable bug fixes#

A few of the more consequential correctness fixes in this release (see Bug Fixes below for the full list):

  • families.Binomial.deriv() was missing a division by n and returned an incorrect value; it now correctly returns 1 - 2 * mu / n. PR #9862

  • The log-likelihood computation for ETSModel was corrected. PR #9400

  • A state space model transition-timing bug was fixed. PR #9688

  • anova_lm silently returned NaN p-values when models were passed in reverse order. PR #9852

  • Numerical instability in VIF was fixed by standardizing the design matrix before computing it. PR #9835

Breaking Changes and Deprecations#

seed/random_state -> rng (SPEC-007)#

As described above, wherever a function or model previously accepted seed or random_state to control randomness, it now accepts rng instead. The old keyword names still work but emit a FutureWarning pointing at rng; they will be removed in a future release. If your code passes seed= or random_state= by keyword to statsmodels functions, you should switch to rng= to avoid the warning (and future breakage). Positional usage is unaffected in most cases since rng occupies the same position the old keyword did.

Minimum dependency versions raised#

  • NumPy: 1.18 -> 1.22.3

  • SciPy: 1.4 -> 1.8

  • pandas: 1.0 -> 1.4

  • patsy: 0.5.2 -> 0.5.6

  • formulaic: new required runtime dependency, >=1.1.0

  • Building from source now requires NumPy >= 2.0, SciPy >= 1.13, and Cython >= 3.0.13 (see the meson-python migration above). This does not affect users installing wheels from PyPI.

Deprecated parameters removed entirely#

The following previously-deprecated (not previously-working) parameters and behaviors were removed as part of a general deprecation clean-up (PR #9936):

  • grangercausalitytests: the verbose parameter (deprecated since 0.14) has been removed. The function no longer prints results; use the returned dictionary as before.

  • AutoReg/ar_select_order: the old_names parameter (pre-0.12 variable naming, deprecated since 0.13) has been removed.

  • kpss: passing nlags=None now raises a ValueError instead of warning and silently falling back to 'auto'. Pass 'auto', 'legacy', or an explicit integer.

  • A number of internal compatibility shims for very old NumPy/SciPy/Python versions were removed from statsmodels.compat, including compat.numpy.lstsq, NP_LT_114, compat.python.asstr, asunicode, lfilter, and compat.scipy.SP_LT_16/SP_LT_17 (along with the vendored multivariate_t fallback they guarded). These were internal implementation details, not public API, but could have been imported directly.

Vendored pandas private APIs#

pandas has been privatizing or removing several small utilities that statsmodels relied on (cache_readonly, deprecate_kwarg, Appender, Substitution). statsmodels now vendors its own copies of these (in statsmodels.compat.pandas and statsmodels.tools.docstring_helpers) so behavior stays stable across pandas versions, including pandas 3. PR #9615, PR #9820, PR #9831

Other removals#

  • The long-empty statsmodels.interface package was removed. PR #9721

  • _lazywhere was removed in favor of apply_where. PR #9543

  • scipy.interpolate.interp2d (removed upstream in recent SciPy) is no longer relied on by TableDist. PR #9832

New Features and Enhancements#

Enhancements

  • Outlier-robust covariance estimation. PR #8129

  • ccf can optionally return confidence intervals. PR #8782

  • Plot cross-correlations and the auto/cross-correlation matrix. PR #8783

  • Plot the prediction curve over a scatter plot in GLMGamResults.plot_partial. PR #8881

  • Add get_margeff to GLM. PR #8889

  • Add MultivariateLS. PR #8919

  • Faster computation of state space revision impacts. PR #8937

  • Two-sample z-test, unequal-variances case. PR #8959

  • Improve lag selection in pacf. PR #9016

  • Add Cython 3 compatibility. PR #9078

  • GLM models now save the names of input pandas Series. PR #9130

  • Robust: additional tools and norms. PR #9186

  • Add CovDetMCD, CovDetMM, RLMDetSMM, and related estimators. PR #9227

  • Add a "one-sided" alternative for proportion_confint. PR #9249

  • Add an alternative option to confint_poisson. PR #9255

  • Add optional parameters to summary_col to indicate fixed effects. PR #9280

  • Ensure returned arrays are owned (not views). PR #9334

  • Improve precision of a diagnostic printout (mean_diff:.3g). PR #9388

  • Add the Leybourne-McCabe stationarity test. PR #9399

  • Add a sample-size calculation for Wilcoxon/Mann-Whitney tests. PR #9401

  • More reliable casting of pandas data. PR #9407

  • Add an abstracted formula engine supporting patsy and formulaic. PR #9423

  • Add ruff lint support. PR #9453

  • x13_arima_analysis can produce seasonality fit diagnostics. PR #9498

  • Allow the ARDL model to use a "ctt" trend. PR #9518

  • Add plot keyword arguments to qqplot_2samples. PR #9544

  • x13_arima_analysis gained an optional raw spec parameter. PR #9550

  • Support array-like and pandas-like data more broadly. PR #9582

  • Add a “no cross terms” option to White’s heteroscedasticity test. PR #9691

  • Add missing attributes to AutoReg. PR #9750

  • Add a seasonal diagnostic plot to graphics.tsaplots. PR #9787

  • Make tsa.statespace Cython usage compatible with SciPy ILP64 builds. PR #9798

  • Allow seasonal-differencing-only models with non-seasonal estimators. PR #9811

  • Add add_ellipse to graphics, and support passing x/y arrays. PR #9815

  • Add order validation to the Hannan-Rissanen estimator. PR #9819

  • Vendor Appender and Substitution docstring helpers from pandas. PR #9820

  • Vendor cache_readonly and deprecate_kwarg from pandas’ private API. PR #9831

  • Report the last root-finder value in the solve_power convergence warning. PR #9885

  • Consistently use rng to move towards SPEC-007. PR #9950

Performance

  • Optimize VECM memory/speed by avoiding an \(O(T^2)\) projection matrix. PR #9720

Notable Bug Fixes#

  • Fix a typo in the InfeasibleTestError exception string. PR #8878

  • Correct diagnostics for changes in pandas. PR #8887

  • MNLogit Wald tests: fix ravel, string cov_names. PR #8907

  • Fix writing a read-only array under pandas 2 copy-on-write. PR #8942

  • Fix an issue in seasonal.py. PR #9029

  • Ensure ARIMA simulation is reproducible. PR #9165

  • Fix scale.Huber and add a robust M-scale. PR #9210

  • Correct cov_kwargs -> cov_kwds. PR #9240

  • Ensure the Zivot-Andrews test does not overwrite its input. PR #9311

  • Avoid an in-place modification bug. PR #9385

  • Correct resid from UECM. PR #9390

  • Correct the x/y label location in qqplot_2sample. PR #9394

  • Remove an incorrect method assignment in GLM’s summary2. PR #9396

  • Ensure the Hessian is skipped where appropriate. PR #9398

  • Correct the log-likelihood computation for ETSModel. PR #9400

  • Ensure VAR can forecast with 0 lags. PR #9413

  • Correct DatetimeIndex handling. PR #9457

  • Correct handling of PeriodIndex in seasonal_decompose. PR #9461

  • SVAR: fix A/B dtype and a one-parameter score shape bug. PR #9468

  • Fix formula eval depth in model selection. PR #9471

  • Tukey’s HSD: fix an unused variance and add Games-Howell for the unequal-variance case. PR #9487

  • Fix a bug in Runs.runs_test for the case of a single run. PR #9524

  • Make the Binomial family more robust to the corner case mu=0, endog=0. PR #9581

  • Fix the add_trend error message to correctly identify constant columns. PR #9636

  • Fix conversion of 1-d arrays to scalars. PR #9673

  • Fix a state space model transition-timing bug. PR #9688

  • Pass alpha through to plot_predict. PR #9728

  • Fix an incorrect length comparison in endpoint transformation logic. PR #9729

  • Fix compilation errors in statespace/meson.build. PR #9738

  • Fix patsy eval_env handling in FormulaManager. PR #9739

  • Raise an error for invalid endog input in emplike.DescStat. PR #9747

  • Add an informative error message when Hessian inversion fails in fit_regularized. PR #9757

  • Replace bare except clauses with except Exception. PR #9758

  • Treat empty docstrings as None in the Docstring class. PR #9773

  • Fix use_boxcox control flow in ExponentialSmoothing.fit. PR #9797

  • Override the resid property in UECMResults. PR #9812

  • Avoid a division by zero in estimate_location. PR #9814

  • L-BFGS-B: respect disp=False instead of always printing output. PR #9823

  • Remove a dead assignment to cov_p in GLM’s fit. PR #9826

  • Fix the GLMInfluence.hat_matrix_diag method name. PR #9830

  • Fix VIF numerical instability by standardizing the design matrix. PR #9835

  • Skip summary diagnostics when slim=True. PR #9844

  • Fix anova_lm silently returning NaN p-values when models are passed in reverse order. PR #9852

  • Set k_exog_user on SVARResults so summary() works. PR #9853

  • Fix Binomial.deriv() to correctly return 1 - 2*mu/n (it was missing the division by n). PR #9862

  • Record the robust scale in RLM.fit_history. PR #9866

  • Fix the NegativeBinomial check for the optional alpha parameter. PR #9877

  • Return nan from Power.solve_power when it fails to converge, rather than a misleading value. PR #9884

  • Correct several parameter names in docstrings (prob_infl, bin_edges, pred_kwds, param_nums, mu1_low). PR #9886

  • Fix DiscreteResults crashing with full_output=0. PR #9887

  • Fix an ccovf shape mismatch for arrays of different lengths. PR #9888

  • describe/Description now handle a 0-row (empty) input gracefully. PR #9899

  • Fix an issue with random generation. PR #9901

  • Attach mlefit attributes to the results instance so they appear in dir(). PR #9902

  • Do not pass hess to L-BFGS-B/TNC in _fit_minimize, which do not accept it. PR #9908

  • Read the entropy integration limits from the kernel. PR #9919

  • Populate _retain_cols in out_of_sample without requiring a prior in_sample call. PR #9920

  • Correct a test that relied on the removed random-state singleton. PR #9924

  • Fix an import failure when matplotlib is not installed. PR #9925

  • Unify group_sums orientation and fix group_demean. PR #9933

Build, Packaging, and Infrastructure#

  • Migrate the build backend from setuptools/setup.py to meson-python. PR #9634

  • Update minimum dependency versions (multiple passes). PR #9110, PR #9112

  • Add experimental Pyodide/WebAssembly support and CI jobs, including fixing an OpenBLAS symbol error under Emscripten. PR #9270, PR #9343

  • Avoid non-deterministic ordering in include_dirs lists (reproducible builds). PR #9296

  • Further clean-up of the build configuration. PR #9632

  • Generate free-threading (no-GIL) compatible Cython modules. PR #9717

  • Ensure the libm C math library is linked for all build targets. PR #9778

  • Remove the oldest-supported-numpy build workaround now that NumPy 2 is the floor for building from source. PR #9312

  • CI: add Python 3.13/3.14 (including free-threaded 3.14t) jobs, drop active Python 3.9 testing, and pin GitHub Actions to full commit SHAs for supply chain hardening. PR #9547, PR #9656, PR #9709, PR #9913, PR #9843

  • Routine dependency updates for GitHub Actions were kept current via dependabot throughout the release cycle (actions/checkout, actions/setup-python, actions/setup-node, github/codeql-action, pypa/cibuildwheel, r-lib/actions/setup-pandoc, and ts-graphviz/setup-graphviz) across roughly two dozen pull requests not individually itemized here.

Documentation#

In addition to numerous individual typo, notebook, and docstring corrections, this release cycle included a large, systematic effort to bring docstrings across the codebase in line with the numpydoc standard (module by module: discrete, genmod, stats, tsa/ statespace, base/compat/datasets, graphics, imputation/multivariate/nonparametric, emplike/duration, treatment/gam, tools, othermod/regression/robust, and more), plus a documentation theme change to pydata-sphinx-theme and a pass over example notebooks to fix formatting and broken links.

Testing, Linting, and Maintenance#

A substantial amount of routine maintenance went into keeping the test suite green against upstream changes in NumPy, SciPy, and pandas (including pandas copy-on-write and preparation for pandas 3), adopting ruff for linting in addition to flake8, running isort/pyupgrade across the codebase, relaxing overly tight test tolerances, and improving thread safety of the test suite ahead of free-threaded CPython support. Selected items:

Development summary and credits#

Thanks to everyone who contributed code, documentation, bug reports, and review to this release cycle. The following list of contributors is generated from git log between v0.15.0.dev0 and the current development head, and may not be complete or fully deduplicated across differently-configured git identities:

Aditi Juneja, Adrian Ross, Agriya Khetarpal, Alex Alborghetti, Andrés, Andrés López, Anh Trinh, Aniket, Aniket Singh Yadav, Anselm Hahn, Antoine Mayerowitz, Anuraag Pandhi, Artem Glebov, Ben, Benjamin Leff, Bortlesboat, Caleb Lindgren, Chad Fulton, Christine P. Chai, Clément Fauchereau, Daan Knoope, David Ivanov, Deshan, Dhairya Motta, Dhruvil Darji, Eden Rochman, Elton Chang, Erich Morisse, Eugen Goebel, Evan Lyall, Evgeni Burovski, FuturMix, Hadi Dayekh, Harish Bhavandla, IsaacP, IntegralIndefinida, Illia Polovnikov, Iman, Jesse W. Collins, Jim Varanelli, Joey Scanga, Josef Perktold, Joshua Markovic, Justin Mahlik, Kaif, Kevin Sheppard, Kevin Gregory, Kumar Aditya, Lakshmi786, Luke J, Maciej Skorski, Manlai Amar, Marc Bresson, Mathias Hauser, Maxime Gourguechon, Melissa Wu, Michał Górny, Michel de Ruiter, Naimish Machchhar, Pranav Achar, Puneet Dixit, Rahul Rathnavel K, Ralf Gommers, Rebecca N. Palmer, RoyS, Sebastian Pölsterl, Shamus, Solaris-star, Sreekant Baheti, Tartopohm, Vedant Madane, Vikram Kumar, Viktor, Vitaliy, Wali Reheman, Will Tirone, YangWu1227, Zbigniew Jędrzejewski-Szmek, Zhengbo Wang, and many others.

These lists are automatically generated based on git log and may not be complete.