This document generates synthetic panel data with known DGP parameters, estimates FE / IFE / MC in both R fect and Python pyfector (1000 bootstrap), and compares ATT, betas, SEs, and p-values side by side.
import sysprint(f"True ATT : 1.5")print(f"True beta : X1=0.8, X2=-0.5, X3=0.3\n")for scenario, slab in [("full", "Balanced"), ("drop", "5% Dropped")]: n_total = n_sig = n_close =0for mname in ["fe", "ife", "mc"]: r = r_res.get((scenario, mname)); py = py_res.get((scenario, mname))ifnot r or py isNone: continue n_total +=1def sig(p):if p <0.01: return"***"if p <0.05: return"**"if p <0.1: return"*"return""if sig(r["p"]) == sig(py.inference.att_avg_pval): n_sig +=1ifabs(r["att"]) >0.01andabs(py.att_avg - r["att"]) /abs(r["att"]) <0.10: n_close +=1print(f"--- {slab} ---")print(f" Models compared : {n_total}")print(f" Significance match : {n_sig}/{n_total}")print(f" ATT within 10% of R : {n_close}/{n_total}\n")print(f"Python: {sys.version.split()[0]} | pyfector: {pyfector.__version__} | numpy: {np.__version__}")
True ATT : 1.5
True beta : X1=0.8, X2=-0.5, X3=0.3
--- Balanced ---
Models compared : 3
Significance match : 3/3
ATT within 10% of R : 3/3
--- 5% Dropped ---
Models compared : 3
Significance match : 3/3
ATT within 10% of R : 2/3
Python: 3.12.3 | pyfector: 0.1.0 | numpy: 2.4.4