diff_diff.TreatmentDoseShape#
- class diff_diff.TreatmentDoseShape[source]#
Bases:
objectDistributional shape of a continuous treatment dose.
Populated on
PanelProfileonly whentreatment_type == "continuous";Noneotherwise. Most fields are descriptive distributional context.profile_panel only sees the dose column, not the separate
first_treatcolumnContinuousDiD.fit()consumes. In the canonicalContinuousDiDsetup (Callaway, Goodman-Bacon, Sant’Anna 2024) the doseD_iis time-invariant per unit (D_i = 0for never-treated,D_i > 0constant across all periods for treated unit i) andfirst_treatis a separate column the caller supplies — not derived from the dose column. Under that canonical setup, several profile-side facts on the dose column predictContinuousDiD.fit()outcomes:PanelProfile.has_never_treated == True(some unit has dose 0 in every period). Predicts the estimator’sP(D=0) > 0requirement under bothcontrol_group="never_treated"andcontrol_group="not_yet_treated"(Remark 3.1 lowest-dose-as-control not yet implemented), because the canonical setup tiesfirst_treat == 0toD_i == 0. Failure means no never-treated controls exist on the dose column; see routing notes below.PanelProfile.treatment_varies_within_unit == False(per-unit full-path dose constancy on the dose column). This IS the actual fit-time gate, matchingContinuousDiD.fit()’sdf.groupby(unit)[dose].nunique() > 1rejection at line 222-228; holds regardless offirst_treat.TruerulesContinuousDiDout — for graded-adoption panels with dose changes useHeterogeneousAdoptionDiD.PanelProfile.is_balanced == True. Actual fit-time gate (continuous_did.py:329-338); notfirst_treat-dependent.Absence of the
duplicate_unit_time_rowsalert. The precompute path silently resolves duplicate(unit, time)cells via last-row-wins (continuous_did.py:818-823); not a fit-time raise. The agent must deduplicate before fit becauseContinuousDiDwill otherwise overwrite silently.treatment_dose.dose_min > 0(over non-zero doses). PredictsContinuousDiD.fit()’s strictly-positive-treated- dose requirement (raisesValueErroron negative dose forfirst_treat > 0units,continuous_did.py:287-294). Failure means some treated units have negative dose; see routing notes below.
Routing alternatives when (1) or (5) fails:
When (1) fails (no never-treated controls but all observed doses non-negative):
ContinuousDiDdoes not apply (Remark 3.1 lowest-dose-as-control is not implemented).HeterogeneousAdoptionDiDIS a candidate for graded-adoption designs (HAD’s contract requires non-negative dose, satisfied here); linear DiD with the treatment as a continuous covariate is another.When (5) fails (negative treated doses):
HeterogeneousAdoptionDiDis not a fallback either — HAD raises on negative post-period dose (had.py:1450-1459, paper Section 2). Linear DiD with the treatment as a signed continuous covariate is the applicable routing alternative.Re-encoding the treatment column (shifting, absolute value, etc.) is an agent-side preprocessing choice that changes the estimand and is not documented in REGISTRY as a supported fallback; if the agent re-encodes to non-negative support, both
ContinuousDiDandHeterogeneousAdoptionDiDbecome candidates again on the re-encoded scale.Do not relabel positive- or negative-dose units as
first_treat == 0: that triggersContinuousDiD.fit()’s force-zero coercion path, which is implementation behavior for inconsistent inputs (e.g., an accidentally-nonzero row on a never-treated unit), not a documented routing option.
The agent must still validate the supplied
first_treatcolumn independently: it must contain at least onefirst_treat == 0unit (P(D=0) > 0), be non-negative integer-valued (or+inf/ 0 for never-treated), and be consistent with the dose column on per-unit treated/untreated status.profile_paneldoes not seefirst_treatand cannot validate it.has_zero_doseis a row-level fact (“at least one observation has dose == 0”); it is NOT a substitute forhas_never_treated, which is the unit-level field. A panel can havehas_zero_dose == True(pre-treatment zero rows) whilehas_never_treated == False(every unit eventually treated), in which case the standard-workflow agent would conclude no never-treated controls exist before callingContinuousDiD.fit().Methods
__init__(n_distinct_doses, has_zero_dose, ...)Attributes
n_distinct_doseshas_zero_dosedose_mindose_maxdose_mean- __init__(n_distinct_doses, has_zero_dose, dose_min, dose_max, dose_mean)#
- classmethod __new__(*args, **kwargs)#