Untreated-only estimation with missing observations and treatment reversals
FEImputation estimates an additive unit/time outcome model using only observed, positive-weight untreated cells. It predicts the counterfactual for observed treated cells and averages their outcome gaps. This is the FEct point-estimation workflow, not ordinary TWFE regression with a treatment coefficient and not an interactive-factor estimator.
The reported ATT is the weighted mean of Y_{it}-\widehat Y_{it}(0) over observed treated cells. Unit/time summaries use the corresponding subsets; periods or units with no evaluated treated cells receive NaN. Altering treated outcomes cannot change the fitted counterfactual.
Causal interpretation requires an appropriate untreated-outcome model and exogeneity assumptions. Treatment may switch on and off mechanically, but that does not validate a no-carryover or no-anticipation assumption. This class provides point estimates only: it does not report standard errors, confidence bands, pretrend tests, or automatic model selection.
{'att': 1.4851976153467064, 'n_train': 269, 'n_treated': 72, 'n_reversing_units': 15, 'inference': 'not_implemented'}
ATT by period: [ nan nan nan nan nan 1.48746046
1.50384742 1.46288531 nan nan 1.46684898 1.50511684]
Code
before = model.predict()changed = y.copy()changed[s['evaluation_mask']] +=100model.fit(changed, d, x, observed=observed)np.testing.assert_allclose(model.predict(), before, equal_nan=True)print('Counterfactuals unchanged after perturbing treated outcomes.')
Counterfactuals unchanged after perturbing treated outcomes.
Array contract and diagnostics
model = cm.FEImputation(tolerance=1e-10, max_iterations=1000)model.fit(y, treatment, x=None, observed=None, sample_weight=None)model.predict() # N x T counterfactuals, NaN at excluded cellsmodel.summary()
y, treatment: float64, shape (units, periods). Treatment must be exactly zero or one on observed cells. Use chronological columns; this matrix API does not infer calendar spacing or validate long-form IDs.
x: optional float64, shape (units, periods, covariates); omit for FE only. Covariates must be finite at positive-weight observed cells.
observed: optional Boolean matrix. Default: finite entries of y. With an explicit mask, masked cells may contain arbitrary values and are ignored; observed outcomes must be finite. A real zero is never treated as missing.
sample_weight: optional finite nonnegative float64 matrix. Zero-weight cells are excluded from both fitting and the ATT. Positive weights affect both.
Summary includes the exact training/evaluation masks, coefficients, ATT, unit/time aggregations, effects, untreated RMSE, counts, and absorption iterations/residual norms. Only evaluated treated cells have finite effects.
Prediction fails for an unseen FE level or a combination crossing disconnected components of the untreated unit/time graph. Gauge-dependent extrapolation is not an identified counterfactual. Collinear covariates also raise an error.
A failed refit clears old fitted state. Insufficient solver budgets raise an error rather than return apparently successful estimates.
The Rust implementation uses compact FE IDs and sparse absorption via within; it does not construct a dense unit/time dummy design. Dense storage of the outcome/covariate matrices is still required.
Independent reference checks
The original, redistributable fixtures in tests/fixtures/yqx_panel/ are generated by base R lm, with and without weights. The standard test suite compares full counterfactual surfaces, coefficient vectors, aggregation and leakage behavior.
tests/test_yqx_lecture_replications.py additionally replays the five available lecture/author-data FEct examples against saved R outputs. These tests require the ignored replication cache and otherwise skip; CI does not download data. The Bischof reference uses a looser R solver tolerance, so surface agreement is checked at 10^{-6} rather than forced to machine precision.
IFEct, treatment-aware matrix completion, heterogeneous-DID estimators, and cluster/event-study inference remain separate work in the replication spec.