diff_diff.RDDensityTest#

class diff_diff.RDDensityTest[source]#

Bases: BaseEstimator

Manipulation testing via local polynomial density estimation (rddensity 3.0 parity).

Tests the null of NO discontinuity in the running variable’s density at the cutoff (McCrary 2008’s question) with the boundary-adaptive local polynomial density estimator of Cattaneo, Jansson & Ma (2020) and robust bias-corrected inference: density estimators of order q = p + 1 are evaluated at bandwidths selected as MSE-optimal for the order-p estimator. Defaults reproduce R rddensity(X): p=2, triangular kernel, jackknife variance, unrestricted model, bwselect="comb", mass-point adjustment on.

Assumptions (CJM 2020 Assumption 1, held separately on each side of the cutoff): the observations are an i.i.d. random sample, and the running variable’s distribution function is smooth with a POSITIVE density near the cutoff on each side. The jackknife/plugin variances assume cross-observation independence - clustered, survey-weighted, or repeated-observation dependence is NOT supported by the reviewed theory and there is no cluster= surface here. Interpret non-rejection as “no density discontinuity detected”, which supports but never proves the RD continuity assumptions; a significant test is evidence of sorting around the cutoff.

Parameters:
  • cutoff (float, default 0.0) – The threshold c in the support of the running variable.

  • p (int, default 2) – Local polynomial order for the density point estimators (1..7, R’s accepted surface).

  • q (int or None, default None) – Order for the bias-corrected estimators; None resolves to p + 1 at fit time (R uses a q=0 sentinel). An explicit q must satisfy q >= p; q == p gives the conventional (uncorrected) test, which OVER-REJECTS at data-driven MSE-optimal bandwidths (CJM 2020 Section 4) - valid conventional inference requires a manually undersmoothed h, the caller’s responsibility (a fit-time warning fires when h is data-driven).

  • fitselect (str, default "unrestricted") – "unrestricted": separate model on each side. "restricted": equal distribution function and higher-order derivatives across the cutoff (only the density may jump); requires equal bandwidths and forbids bwselect="each".

  • kernel (str, default "triangular") – “triangular”, “epanechnikov”, or “uniform” (R spellings “tri”/”epa”/”uni” accepted).

  • vcov_type (str, default "jackknife") – Variance estimator: “jackknife” (R’s default; the SA Section 5.2 leave-one-out construction, window-restricted as in R) or “plugin” (asymptotic plug-in).

  • h (float or (float, float) or None, default None) – Manual bandwidth(s). A scalar applies to both sides; a pair is (h_left, h_right). None selects data-driven bandwidths.

  • bwselect (str, default "comb") – Bandwidth selection: “each” (per-side MSE), “diff” (MSE of the difference), “sum” (MSE of the sum), “comb” (median of each/diff/sum per side for the unrestricted model; min of diff/sum for the restricted model). Ignored when h is supplied.

  • masspoints (str, default "adjust") – Mass-point handling: “adjust” (R massPoints=TRUE - the EDF is computed on unique values and replicated back, with a warning), “check” (detect repeated values and warn WITHOUT adjusting - estimation matches R massPoints=FALSE), “off” (no detection). String surface matching the RD-family masspoints domain (documented Deviation from R’s boolean).

  • regularize (bool, default True) – Local sample-size regularization of the data-driven bandwidths.

  • n_local_min (real or None, default None -> 20 + p + 1) – Minimum observations in each local neighborhood (final-stage floor). ceil() is applied as in R; ceil(value) >= 0 required, 0 disables the gate. Must be finite (Deviation from R, which accepts Inf).

  • n_unique_min (real or None, default None -> 20 + p + 1) – Minimum unique observations in each local neighborhood; same contract as n_local_min.

  • report_all (bool, default False) – Also compute and report the conventional (order-p) test alongside the robust one (R’s all=TRUE). The conventional test’s inference carries the same over-rejection caveat as q == p at data-driven bandwidths (see q above).

Examples

>>> test = RDDensityTest(cutoff=0.0)
>>> result = test.fit(df, running="score")
>>> result.t_stat, result.p_value  # robust bias-corrected test

Methods

__init__([cutoff, p, q, fitselect, kernel, ...])

fit(data, running)

Run the manipulation test on data[running].

get_params([deep])

Get estimator parameters (sklearn-compatible).

set_params(**params)

Set estimator parameters (sklearn-compatible, transactional).

__init__(cutoff=0.0, p=2, q=None, fitselect='unrestricted', kernel='triangular', vcov_type='jackknife', h=None, bwselect='comb', masspoints='adjust', regularize=True, n_local_min=None, n_unique_min=None, report_all=False)[source]#
Parameters:
classmethod __new__(*args, **kwargs)#