R-style regression diagnostic plots (plot(lm)) for statsmodels and scikit-learn
Project description
regdiag
R's plot(lm_model) for Python — one line, works with both statsmodels and scikit-learn.
R has a famous one-liner for regression diagnostics: plot(lm_model) produces four
classic diagnostic plots (Residuals vs Fitted, Normal Q-Q, Scale-Location, Residuals
vs Leverage). Python has never had a clean equivalent — the pieces exist scattered
across statsmodels (only works on its own OLS objects) and a few small,
low-traction packages. regdiag fills that gap.
from sklearn.linear_model import LinearRegression
import regdiag
model = LinearRegression().fit(X, y)
regdiag.diagnose(model, X, y)
Why regdiag
- One line, R-style output.
regdiag.diagnose(model, X, y)gives you the full 4-panel figure, same asplot(lm). - Works with statsmodels and scikit-learn. Any sklearn estimator exposing
.coef_/.intercept_(LinearRegression, Ridge, Lasso, ElasticNet, SGDRegressor, BayesianRidge, ...) or a statsmodelsOLSresults object. statsmodelsis fully optional. Core dependencies are just numpy, scipy, matplotlib, and scikit-learn. VIF and the Breusch-Pagan test are computed with plain numpy/scipy — no statsmodels needed at runtime, even though it's the library people usually reach for to get those numbers.- Honest about black-box models. Pass a
RandomForestRegressoror any other model that only exposes.predict()andregdiagswitches to a clearly-labeled generic mode (Residuals vs Fitted, Residual Distribution, Actual vs Predicted). It will never compute leverage or Cook's distance for a model where the hat-matrix math doesn't apply — those statistics are only well-defined for linear models.
Install
pip install regdiag
# with statsmodels support (accept statsmodels OLS objects as input):
pip install "regdiag[statsmodels]"
Quickstart
import numpy as np
from sklearn.linear_model import LinearRegression
import regdiag
rng = np.random.default_rng(0)
X = rng.normal(size=(200, 3))
y = 1.0 + X @ np.array([2.0, -1.5, 0.5]) + rng.normal(scale=1.0, size=200)
model = LinearRegression().fit(X, y)
diag = regdiag.diagnose(model, X, y) # fits nothing, model must already be fit; shows the 4-panel plot
print(diag.summary()) # Breusch-Pagan test, VIF table, top Cook's-distance points
Also works directly with statsmodels:
import statsmodels.api as sm
X_const = sm.add_constant(X)
results = sm.OLS(y, X_const).fit()
regdiag.diagnose(results, X, y)
And degrades gracefully for black-box models instead of lying about statistics:
from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor().fit(X, y)
diag = regdiag.diagnose(rf, X, y) # 3-panel generic residual analysis
diag.vif() # raises NotLinearModelError — VIF isn't defined here
API
regdiag.diagnose(model, X, y, *, feature_names=None, plot=True,
figsize=(10, 8), annotate=True, n_annotate=3, save=None)
Returns a RegressionDiagnostics object:
| Attribute / method | Linear mode | Generic mode |
|---|---|---|
.residuals, .fitted_values |
✅ | ✅ |
.leverage, .cooks_distance, .studentized_residuals |
✅ | None |
.plot() |
4-panel | 3-panel |
.residuals_vs_fitted(), .qq_plot(), .scale_location(), .residuals_vs_leverage() |
✅ | raises NotLinearModelError |
.residual_histogram(), .actual_vs_predicted() |
✅ | ✅ |
.breusch_pagan(), .vif() |
✅ | raises NotLinearModelError |
.summary() |
text report | text report |
Comparison
| regdiag | lmdiag | statsmodels (raw) | yellowbrick | |
|---|---|---|---|---|
| Works with sklearn linear models | ✅ | ✅ | ❌ | ✅ |
| Works with statsmodels OLS | ✅ | ✅ | ✅ | ❌ |
| statsmodels is optional at runtime | ✅ | ❌ | n/a | ✅ |
| Built-in VIF / Breusch-Pagan | ✅ | ❌ | ✅ (manual) | ❌ |
| Honest black-box fallback (no fake leverage) | ✅ | ❌ | ❌ | partial |
One-object API (diagnose(model, X, y)) |
✅ | functions | manual | partial |
Statistical notes
- Leverage is computed via QR decomposition of the design matrix (never forms the
full
n × nhat matrix). - Cook's distance uses the classic OLS-based formula. It's applied uniformly to any linear-coefficient model (including Ridge/Lasso) for simplicity, but strictly its "influence on fitted coefficients" interpretation assumes an OLS estimator — interpret with some caution for heavily regularized models.
- Rank-deficient design matrices (collinear columns) and
n ≤ pdatasets raise a clear error rather than emittingNaN/infsilently. statsmodelsWLS/GLS results are not supported in v1 (OLS only).
See CHANGELOG.md for release notes and CONTRIBUTING.md to get set up for
development.
License
MIT — see LICENSE.
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 regdiag-0.1.1.tar.gz.
File metadata
- Download URL: regdiag-0.1.1.tar.gz
- Upload date:
- Size: 242.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
03d80d82e94e5146b56ae5c070197053b29897218fcf25a245b418e874c6538a
|
|
| MD5 |
a88c842156642d7342b5054606889b97
|
|
| BLAKE2b-256 |
88e277599098a8f44675f41e415ef905c5ead707f54aa04f5cb5b8a5469303ed
|
Provenance
The following attestation bundles were made for regdiag-0.1.1.tar.gz:
Publisher:
publish.yml on SparksFlash/regdiag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
regdiag-0.1.1.tar.gz -
Subject digest:
03d80d82e94e5146b56ae5c070197053b29897218fcf25a245b418e874c6538a - Sigstore transparency entry: 2056784398
- Sigstore integration time:
-
Permalink:
SparksFlash/regdiag@b45a4ba5d0130ecaa762e050eb35027074ca206a -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/SparksFlash
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b45a4ba5d0130ecaa762e050eb35027074ca206a -
Trigger Event:
push
-
Statement type:
File details
Details for the file regdiag-0.1.1-py3-none-any.whl.
File metadata
- Download URL: regdiag-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
88b0bc8c10aede2f6f66a4d4dbedc952a7cbe6ca610b315c97987fb60313a454
|
|
| MD5 |
e6c500a965be6bbe7fc4818d7aab6837
|
|
| BLAKE2b-256 |
966531984cd753bb95f667d3feaa38374bf922bc97df88874e09450c9015ea2a
|
Provenance
The following attestation bundles were made for regdiag-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on SparksFlash/regdiag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
regdiag-0.1.1-py3-none-any.whl -
Subject digest:
88b0bc8c10aede2f6f66a4d4dbedc952a7cbe6ca610b315c97987fb60313a454 - Sigstore transparency entry: 2056784938
- Sigstore integration time:
-
Permalink:
SparksFlash/regdiag@b45a4ba5d0130ecaa762e050eb35027074ca206a -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/SparksFlash
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b45a4ba5d0130ecaa762e050eb35027074ca206a -
Trigger Event:
push
-
Statement type: