SPB Git

spb/wp29_uqo

Public

# 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, matching se_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).
Files · main
Menu

Theme