F2-dev-01 — Two-way FE slope with firm-clustered uncertainty
Question
Estimate β in y_it = a_i + g_t + β x_it + u_it (firm and year effects unrestricted), with standard errors robust to arbitrary dependence within firm over time.
Data and exclusions
data/firm_panel.csv (synthetic), 1200 rows read (n_input_rows). Balanced panel of 100 firms (n_firms) × 12 years 2008–2019 (n_years); no missing values, no duplicate firm–year keys, so no rows were excluded (out/exclusions.csv; data_issues is empty). All 1200 observations are analysed (n_analysed).
Method
- Baseline: pooled OLS of y on x with an intercept (
beta_pooled). - Two-way FE: OLS with firm and year dummies (LSDV) (
beta_fe); checked against the two-way within (double-demeaning) estimator, which agrees to <1e-10 (beta_fe_within_check). - Conventional SE: homoskedastic OLS SE from the LSDV fit, residual df = N − G − T = 1088 (
se_conventional). - Clustered SE: firm-clustered sandwich (CR1) via Frisch–Waugh–Lovell, small-sample factor G/(G−1)·(N−1)/(N−K) with K = 12 (slope + 11 year effects; firm effects are nested in clusters and not counted, as in Stata
xtreg, fe/reghdfe) (se_cluster,cluster_small_sample_factor). - 95% CI: beta_fe ± t_{0.975, G−1} · se_cluster, with G−1 = 99 df (
ci_critical_value_t,ci_df). - No randomness (
random_seed= null).
Results
- Pooled baseline slope: 1.268 (
beta_pooled). - Two-way FE slope: 0.6045 (
beta_fe). - The FE estimate is about half the pooled slope. That gap is consistent with firm and/or year effects being correlated with x, which biases the pooled estimate upward. The data do not identify which of the two kinds of effect drives it.
Uncertainty
- Conventional SE 0.0326 (
se_conventional); firm-clustered SE 0.0450 (se_cluster). The ratio is 1.38 (se_ratio_cluster_to_conventional), which points to positive within-firm dependence of the residuals and/or regressor. - 95% CI for β (clustered): [0.515, 0.694] (
beta_ci_low,beta_ci_high). - Sensitivity: if all 112 LSDV parameters are counted in K (intercept, slope, 99 firm and 11 year dummies), as statsmodels does by default on the LSDV fit, the clustered SE is 0.0471 (
se_cluster_lsdv_all_dummies_counted, matchingse_cluster_statsmodels_lsdv). This is a convention difference and does not change the conclusions.
Limitations and open issues
- The data are synthetic. β is a within-firm, within-year association; a causal reading would need strict exogeneity of x given the fixed effects, which cannot be tested here.
- With G = 100 clusters, cluster-robust inference should be reasonably reliable, but it is still asymptotic. Wild-cluster bootstrap was not run because the task does not require it.
- The clustered SE depends on which degrees-of-freedom correction is used, by about 4.5% (see Uncertainty). The primary choice is documented above.
- Feasibility: complete (
feasibility).