Skip to main content

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.

binspect

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

binspect_regression-0.1.1.tar.gz (334.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

binspect_regression-0.1.1-py3-none-any.whl (49.5 kB view details)

Uploaded Python 3

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

Hashes for binspect_regression-0.1.1.tar.gz
Algorithm Hash digest
SHA256 5c3055f9f89d5531506fb14b5e0e20ddc0a4a335bf363fd48b54a9ead90aebbc
MD5 bbab1cff363c87d3d3458a12e35675f0
BLAKE2b-256 e19abedae36ba5c5534933f37c9aae31251e8c5c24b6c0c15dc7ad631eda0fa6

See more details on using hashes here.

Provenance

The following attestation bundles were made for binspect_regression-0.1.1.tar.gz:

Publisher: release.yml on joshuamyers22/binspect

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file binspect_regression-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for binspect_regression-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 42702c3657d495c0553eae1b20b659ba1eb78feff92b9006de9112aee5f517f7
MD5 3fac4353c782d2e9968dfc7bd646cacb
BLAKE2b-256 339d132265bd78c0fe4a30d2b150bf254e77fd3c067602e19949c5fe575b74bb

See more details on using hashes here.

Provenance

The following attestation bundles were made for binspect_regression-0.1.1-py3-none-any.whl:

Publisher: release.yml on joshuamyers22/binspect

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.2

2 files

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page