binspect
Binned scatterplots for linear specification diagnostics.
binspect estimates binned conditional means and compares them with a linear fit to
the underlying observations. The bin means are the fitted values from the saturated
model OLS(y ~ C(bin)). Their weighted deviations from the line provide a descriptive
linear specification diagnostic.
import binspect
bs = binspect.binscatter(df, y="sales", x="age", bins=20)
bs.table # per-bin means, SDs, standard errors, intervals
bs.summary_frame() # one-row model and diagnostic table
bs.to_dict() # JSON-compatible structured results
print(bs.summary())
bs.plot(theme="paper")
bs.audit(theme="paper") # plot plus marginal distributions and residuals
Adjust both variables for numeric or categorical controls with FWL residualization:
adjusted = binspect.binscatter(
df,
y="sales",
x="age",
controls=["region", "tenure"],
bins=20,
)
adjusted.fit.slope # age coefficient from OLS(sales ~ age + region + tenure)
adjusted.plot() # axes are explicitly labelled as adjusted
Residualized variables retain their original means, keeping the plot on a familiar
scale. Categorical controls are indicator-encoded and a constant is included
automatically. With weights=, the projection uses the same reliability weights.
Zero-weight observations are retained by default: they can affect bin boundaries,
unweighted bin counts, and stored descriptive arrays, but never point estimates or
degrees-of-freedom corrections. To make them fully equivalent to omitted rows, set
zero_weight="drop":
trimmed = binspect.binscatter(
df, y="sales", x="age", weights="sample_weight", zero_weight="drop"
)
For comparisons across groups, pooled bin edges are used by default so facets refer
to the same intervals of x:
comparison = binspect.compare(
df,
y="sales",
x="age",
group="region",
bins=20,
)
comparison.table # one row per group and bin
comparison.summary_frame() # one row per group
comparison.plot(sharex=True, sharey=True)
Pass common_bins=False to select bins separately within each group. The pooled
estimate remains available as comparison.pooled.
Use cluster= when observations share shocks within a firm, person, location, or
other sampling unit:
clustered = binspect.binscatter(
df,
y="sales",
x="age",
controls=["region", "tenure"],
cluster="firm_id",
bins=20,
)
This applies CR1 cluster-robust standard errors to both the fitted slope and bin means. Bin-mean intervals use a t reference distribution based on the number of clusters represented in each bin. Bins containing fewer than two positive-weight clusters have undefined intervals.
Related packages
binsreg (Cattaneo, Crump, Farrell, and Feng) provides formal binscatter inference.
binspect delegates optimal bin selection to it when requested. Use binsreg when
uniform confidence bands or formal shape-restriction tests are required.
What it draws
The default plot presents the estimates, uncertainty, linear fit, lack of fit, and distribution of the exogenous variable as separate layers.
| Layer | What it shows | Default |
|---|---|---|
bins |
Bin means — the saturated-model fitted values | on |
ci |
Confidence bar per bin mean | on |
fit |
OLS line through the underlying data | on |
deviation |
Shading between bin means and the line — the lack of fit | on |
rug |
x-density, so quantile bins can't hide their own imbalance | on |
sd_line |
Slope σy/σx — the OLS line is this flattened by r |
off |
smooth |
Local-linear smoother through the bin means | off |
raw |
Underlying observations at low alpha | off |
Three themes are included: notebook (default), paper (thin, serif, grayscale-safe),
and deck (larger marks and type). Themes are colorblind-safe and scoped; importing
binspect does not modify global rcParams.
Use bs.audit() for a composed diagnostic figure with the unchanged binscatter in
the central panel, marginal histograms, and OLS residuals against fitted values.
Either companion view can be omitted with marginals=False or residuals=False.
These panels describe the stored estimate; they do not add a formal specification
test.
One thing to know about η²
The bin-indicator model does not nest the linear model. Consequently, η² can be below
the linear R² when bins are coarse, and their difference is not a valid curvature
measure. binspect reports normalized lack of fit,
SS_lof = Σⱼ nⱼ (ȳⱼ − ŷ(x̄ⱼ))² gap = SS_lof / SS_total
which is nonnegative by construction and corresponds to the deviations shown in the plot. This quantity is descriptive and is not a formal test of linearity.
Status
Initial alpha release (0.1.0). The API may continue to evolve during the 0.x
series. The distribution name is binspect-regression; the import remains binspect.
Not yet implemented: uniform confidence bands and quantile regression. Without
cluster=, standard errors are sd/√n within bin and assume independent
observations.
Install
git clone https://github.com/joshuamyers22/binspect.git && cd binspect
pip install -e ".[dev]"
pytest
Install the published package with pip install binspect-regression and continue to
write import binspect.
For contributing, release checks, and development conventions, see CONTRIBUTING.md. Please report vulnerabilities privately as described in SECURITY.md.
Maintainer release instructions are in RELEASING.md.
License
MIT.
Citation
The methodology this package leans on is Cattaneo, M. D., Crump, R. K., Farrell,
M. H., & Feng, Y. (2024). "On Binscatter." American Economic Review, 114(5),
1488–1514. If you use binned scatterplots for inference, cite that paper and consider
using binsreg directly.
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 binspect_regression-0.1.1.tar.gz.
File metadata
- Download URL: binspect_regression-0.1.1.tar.gz
- Upload date:
- Size: 334.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c3055f9f89d5531506fb14b5e0e20ddc0a4a335bf363fd48b54a9ead90aebbc
|
|
| MD5 |
bbab1cff363c87d3d3458a12e35675f0
|
|
| BLAKE2b-256 |
e19abedae36ba5c5534933f37c9aae31251e8c5c24b6c0c15dc7ad631eda0fa6
|
Provenance
The following attestation bundles were made for binspect_regression-0.1.1.tar.gz:
Publisher:
release.yml on joshuamyers22/binspect
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
binspect_regression-0.1.1.tar.gz -
Subject digest:
5c3055f9f89d5531506fb14b5e0e20ddc0a4a335bf363fd48b54a9ead90aebbc - Sigstore transparency entry: 2773720855
- Sigstore integration time:
-
Permalink:
joshuamyers22/binspect@5d52a1f865718bf741a01228312ba9ee6af71bcf -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/joshuamyers22
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5d52a1f865718bf741a01228312ba9ee6af71bcf -
Trigger Event:
release
-
Statement type:
File details
Details for the file binspect_regression-0.1.1-py3-none-any.whl.
File metadata
- Download URL: binspect_regression-0.1.1-py3-none-any.whl
- Upload date:
- Size: 49.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42702c3657d495c0553eae1b20b659ba1eb78feff92b9006de9112aee5f517f7
|
|
| MD5 |
3fac4353c782d2e9968dfc7bd646cacb
|
|
| BLAKE2b-256 |
339d132265bd78c0fe4a30d2b150bf254e77fd3c067602e19949c5fe575b74bb
|
Provenance
The following attestation bundles were made for binspect_regression-0.1.1-py3-none-any.whl:
Publisher:
release.yml on joshuamyers22/binspect
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
binspect_regression-0.1.1-py3-none-any.whl -
Subject digest:
42702c3657d495c0553eae1b20b659ba1eb78feff92b9006de9112aee5f517f7 - Sigstore transparency entry: 2773720879
- Sigstore integration time:
-
Permalink:
joshuamyers22/binspect@5d52a1f865718bf741a01228312ba9ee6af71bcf -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/joshuamyers22
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5d52a1f865718bf741a01228312ba9ee6af71bcf -
Trigger Event:
release
-
Statement type: