"""F2-smoke-01: OLS slope of y on x with firm-clustered SE. Run from workspace root.""" import json, os import numpy as np, pandas as pd, statsmodels.api as sm from scipy import stats df_raw = pd.read_csv("data/panel.csv") n_input = len(df_raw) issues = [] df = df_raw.copy() na = df[["firm_id", "x", "y"]].isna().any(axis=1) if na.any(): issues.append({"issue": f"{int(na.sum())} rows with missing values", "handling": "dropped"}) df = df[~na] dup = df.duplicated() if dup.any(): issues.append({"issue": f"{int(dup.sum())} exact duplicate rows", "handling": "kept (cannot distinguish from genuine repeats); flagged"}) nonfinite = ~np.isfinite(df[["x", "y"]]).all(axis=1) if nonfinite.any(): issues.append({"issue": f"{int(nonfinite.sum())} non-finite values", "handling": "dropped"}) df = df[~nonfinite] X = sm.add_constant(df["x"].to_numpy()) y = df["y"].to_numpy() g = df["firm_id"].to_numpy() ols = sm.OLS(y, X).fit() cl = sm.OLS(y, X).fit(cov_type="cluster", cov_kwds={"groups": g, "use_correction": True}) G = int(pd.Series(g).nunique()) beta, alpha = float(ols.params[1]), float(ols.params[0]) se_cl = float(cl.bse[1]) tcrit = float(stats.t.ppf(0.975, G - 1)) # t with G-1 df for clustered inference res = { "task_id": "F2-smoke-01", "beta_hat": beta, "alpha_hat": alpha, "se_ols": float(ols.bse[1]), "se_cluster": se_cl, "beta_ci_low": beta - tcrit * se_cl, "beta_ci_high": beta + tcrit * se_cl, "n_analysed": int(len(df)), "n_clusters": G, "feasibility": "complete", "feasibility_reason": None, "data_issues": issues, "n_input_rows": {"panel.csv": int(n_input)}, "random_seed": None, # supplementary diagnostics "se_cluster_ratio_to_ols": se_cl / float(ols.bse[1]), "t_crit_df": G - 1, "t_crit": tcrit, "cluster_sizes_min_max": [int(pd.Series(g).value_counts().min()), int(pd.Series(g).value_counts().max())], } os.makedirs("out", exist_ok=True) with open("out/results.json", "w") as f: json.dump(res, f, indent=2) print(json.dumps(res, indent=2))