Skip to content

statspai.nonparametric

nonparametric

Nonparametric estimation methods.

Provides local polynomial regression (lpoly), kernel density estimation (kdensity), and nonparametric regression (npregress).

KDensityResult

Bases: ResultProtocolMixin

Results from kernel density estimation.

Examples:

>>> import statspai as sp
>>> import numpy as np, pandas as pd
>>> rng = np.random.default_rng(3)
>>> df = pd.DataFrame({"income": rng.normal(10.0, 2.0, 500)})
>>> res = sp.kdensity(df, x="income", kernel="gaussian")
>>> type(res).__name__
'KDensityResult'
>>> bool(res.bandwidth > 0)
True
>>> bool((res.density >= 0).all())
True

plot

plot(ax: Any = None, hist: bool = False, rug: bool = False, **kwargs: Any) -> Any

Plot the kernel density estimate.

LPolyResult

Bases: ResultProtocolMixin

Results from local polynomial regression.

Examples:

>>> import statspai as sp
>>> import numpy as np, pandas as pd
>>> rng = np.random.default_rng(5)
>>> x = rng.uniform(0, 10, 300)
>>> y = np.sin(x) + rng.normal(0, 0.3, 300)
>>> df = pd.DataFrame({"y": y, "x": x})
>>> res = sp.lpoly(df, y="y", x="x", degree=1)
>>> type(res).__name__
'LPolyResult'
>>> res.degree
1
>>> bool(res.bandwidth > 0)
True

plot

plot(ax: Any = None, scatter: bool = True, ci: bool = True, **kwargs: Any) -> Any

Plot the local polynomial fit with optional scatter and CI.

LProbustPoint dataclass

One evaluation point of :func:lprobust_at_point.

Attributes mirror lprobust's e(Result) columns so a reader can line the two up: tau_us is column 5, tau_bc column 6, se_us column 7, se_rb column 8.

Examples:

>>> import numpy as np
>>> import statspai as sp
>>> rng = np.random.default_rng(0)
>>> x = rng.uniform(-1, 1, 500)
>>> y = np.sin(2 * x) + rng.normal(0, 0.3, 500)
>>> point = sp.lprobust_at_point(x=x, y=y, eval_point=0.0, h=0.5)
>>> type(point).__name__
'LProbustPoint'
>>> point.n_eff                      # observations inside the bandwidth
248

The robust bias-corrected standard error is wider than the conventional one, because it also carries the variance of the estimated bias:

>>> bool(point.se_rb > point.se_us)
True

bias property

bias: float

Estimated leading bias, tau_us - tau_bc.

did_had uses this directly rather than the conventional standard error when forming its interval.

lpbwselect_mse_dpi

lpbwselect_mse_dpi(x: ndarray, y: ndarray, eval_point: float, *, kernel: str = 'epanechnikov', p: int = 1, deriv: int = 0, n_neighbors: int = 3, bwcheck: int = 21, bwregul: float = 1.0) -> Dict[str, float]

MSE-optimal direct-plug-in bandwidths, as bwselect('mse-dpi').

Port of nprobust's lpbwselect.mse.dpi. Returns {'h', 'b'} — the main and bias bandwidths that :func:lprobust_at_point takes.

The selector is a ladder: two pilot fits at increasing polynomial order give the bandwidths that a third fit uses to estimate the bias of the fourth, which is the one you asked for. Each rung is clamped into [bw_min, bw_max], where bw_min is the distance to the bwcheck-th nearest observation — without it the ladder can select a bandwidth containing too few points to fit.

Only implemented for the (p - deriv) odd case, which covers the default local-linear level fit (p=1, deriv=0) and everything sp.did_had needs. The even case additionally requires a 1-D numerical optimization of the MSE expansion, and is rejected rather than approximated.

Examples:

>>> import numpy as np, statspai as sp
>>> rng = np.random.default_rng(0)
>>> x = np.abs(rng.gamma(1.4, 0.6, 400))
>>> y = 0.8 + 1.3 * x + rng.normal(0, 0.5, 400)
>>> bw = sp.lpbwselect_mse_dpi(x, y, 0.0)
>>> bw['h'] > 0 and bw['b'] > 0
True
References

calonico2019nprobust, calonico2018effect

lprobust_at_point

lprobust_at_point(x: ndarray, y: ndarray, eval_point: float, h: float, b: Optional[float] = None, *, kernel: str = 'epanechnikov', p: int = 1, deriv: int = 0, n_neighbors: int = 3) -> LProbustPoint

Local polynomial fit at eval_point with robust bias correction.

Parameters:

Name Type Description Default
x ndarray

Running variable and outcome, same length.

required
y ndarray

Running variable and outcome, same length.

required
eval_point float

Where to evaluate the regression function.

required
h float

Main bandwidth, for the order-p fit.

required
b float

Bias bandwidth, for the order-p+1 fit that estimates the leading bias. Defaults to h (rho = 1), which is lprobust's behaviour when only h is supplied.

None
kernel ('epanechnikov', 'triangular', 'uniform', 'gaussian')

Default epanechnikov, matching lprobust.

'epanechnikov'
p int

Polynomial order — 1 is local linear.

1
deriv int

Order of the derivative to report; 0 is the level.

0
n_neighbors int

Neighbours for the nearest-neighbour variance, matching lprobust's vce(nn) default of 3.

3

Returns:

Type Description
LProbustPoint
Notes

The fit uses the union of the h and b windows, so observations only reachable by the larger bandwidth still enter the bias-correction step. Restricting to the h window alone silently drops them and moves tau_bc whenever b > h.

Examples:

>>> import numpy as np, statspai as sp
>>> rng = np.random.default_rng(0)
>>> x = np.abs(rng.gamma(1.4, 0.6, 400))
>>> y = 0.8 + 1.3 * x + rng.normal(0, 0.5, 400)
>>> fit = sp.lprobust_at_point(x, y, 0.0, h=0.8)
>>> bool(fit.se_rb > fit.se_us)  # robust interval is wider
True
References

calonico2019nprobust, calonico2018effect