# Does workforce training raise productivity growth? (F6-conf-04, simulated data) ## Question What is the effect of one additional training hour per employee (programme year) on productivity growth in the following year, in percentage points per hour? Estimand: the causal coefficient on `training_hours`, assuming selection on observables given the pre-programme `skill_index`, and a linear, homogeneous effect. The data are simulated, not observed. ## Data and exclusions `data/firms.csv`: 1200 firms (`n_input_rows`), 4 columns, no missing values and no duplicate firms. 12 rows had negative `training_hours` (`n_excluded_negative_hours`), which is physically impossible. I excluded them from the main analysis (`out/exclusions.csv`, step 2), leaving `n_analysed` = 1188. The excluded rows are kept in a sensitivity check. `skill_index` correlates strongly with both training (r = 0.69) and growth (r = −0.79), so it is a strong confounder (`data_issues`). Full audit: `out/state/data_audit.md`. ## Method - Baseline: OLS of `productivity_growth` on `training_hours` with an intercept, as the task specifies. - Target model: OLS of `productivity_growth` on `training_hours` + `skill_index`. `skill_index` is measured the year before the programme, so it is a valid pre-treatment control and not a mediator. It is the only covariate available, so selection on observables means conditioning on it. - Standard errors: heteroskedasticity-robust (HC1) for every model (`effect_se_type`), with 95% normal-approximation intervals. - Fit metric: RMSE = sqrt(mean(e²)) of the in-sample residuals. - Sensitivity checks: (a) a cubic polynomial in `skill_index`, to probe whether the linear adjustment is misspecified; (b) all 1200 rows, including the negative-hour rows. - No randomness is used (`random_seed` = null). - Outputs: `out/table1.csv` and `out/figure1.png` are produced by `out/analysis.py`. ## Results - **Unadjusted association:** −0.132 pp per hour (`naive_estimate`), 95% CI [−0.160, −0.103] (`naive_ci_low`, `naive_ci_high`). RMSE 3.86 pp (`baseline_metric`). - **Adjusted effect (estimand):** +0.254 pp per hour (`effect_estimate`), 95% CI [0.234, 0.273] (`effect_ci_low`, `effect_ci_high`). RMSE 1.98 pp (`model_metric`). R² rises from 0.07 (`naive_r2`) to 0.76 (`adjusted_r2`). - **Skill coefficient:** −4.62 pp per index unit (`skill_index_coefficient`). - **Sign reversal:** the sign flips from negative to positive once skill is controlled. Higher-skill firms received more training but grew more slowly, so the unadjusted slope is confounded downward. The omitted-variable-bias identity holds exactly in the sample (`out/state/checks.md`). - **Conclusion code:** `positive_effect` (`conclusion`), because the whole 95% interval lies above zero. - **Robustness:** the cubic-skill specification gives 0.254 (`sensitivity_cubic_skill_estimate`). The full 1200-row sample gives 0.252 (`sensitivity_fullsample_effect_estimate`). Both fall inside the main interval. ## Uncertainty - The HC1 SE is 0.0098 (`effect_se`), almost the same as the conventional SE of 0.0098 (`effect_se_conventional`). So there is little sign of heteroskedasticity. - The 95% CI has a half-width of about 0.019 pp per hour, which only covers sampling uncertainty. - It does not cover uncertainty about the identifying assumption (no unobserved confounding) or about the functional form beyond the cubic check. Those are the larger risks, discussed below. ## Limitations and open issues - **Main threat – unobserved confounding.** The causal reading depends entirely on `skill_index` being the only confounder. Anything else that drives both training uptake and growth would bias the estimate: management quality, sector, firm size, credit constraints, or anticipated demand shocks. The file has no other variables, so this cannot be tested. The large shift from the naive to the adjusted estimate shows how sensitive the result is to which confounders are included. I did not run a formal sensitivity analysis for unobserved confounding (e.g. Oster/Cinelli–Hazlett bounds). - **Measurement error in `skill_index`.** If the index measures true skill with noise, controlling for it removes only part of the confounding. Because skill pushes growth down and training up, residual confounding would bias the estimate *downward*, but the size of that bias is unknown. - **Functional form and homogeneity.** I assumed a linear, homogeneous effect. I only checked a cubic in skill (exploration also tried a training×skill interaction, which was small and not significant; it is not reported as a result). I did not test nonlinearity in hours, such as diminishing returns. A heterogeneous effect would make the coefficient a variance-weighted average, not the average treatment effect (ATE). - **Negative training hours.** These 12 rows suggest the data-generating process was not truncated at zero, or that recording errors exist. Excluding them barely changes the estimate (`sensitivity_fullsample_effect_estimate`). However, if the treatment variable has errors, other values could be wrong too, which I cannot check. - **Not checked:** spillovers between firms, attrition or survivorship (only firms with observed growth appear), external validity beyond simulated data, and out-of-sample predictive fit (both RMSEs are in-sample). - **What would invalidate the result:** an unobserved confounder correlated with training conditional on skill; `skill_index` actually being measured after training started (the task states it is pre-programme); or outcome timing that overlaps the programme year.