Research tasks: where to start¶
Ten common applied-econometrics tasks, each with the functions to call, the
options that change the answer, how to check what evidence covers your
configuration, and the mistakes that are easy to make. Every function named
here exists (tests/test_research_tasks_doc.py checks), and every page it
links to goes deeper.
Two habits apply to all of them:
- Read the result card.
sp.result_card(fit)(also in every MCP response) lists the estimand, the rows actually used, the variance convention, the backend, which configuration-level evidence covers this call, and the assumptions the data cannot verify. - Evidence is per configuration. A certified function is not certified
for every option.
sp.validation_scope(fit)says which outputs of this call were compared with R / Stata; the generated capability table summarises the flagship estimators.
1. Moving a Stata .do file¶
Call: sp.stata(...) runs supported estimation / postestimation
commands; sp.from_stata(...) translates. See translator
and grammar.
Semantics to check, not just syntax:
- missing values -- estimators drop incomplete rows listwise (and rows with a
missing cluster, as
vce(cluster));sp.pwcorris pairwise like Stata'spwcorr,listwise=Trueforpwcorr, listwise; - weights --
sp.regress(weights=)is[aw=]; matching estimators take frequency weights ([fw=]); survey work goes throughsp.svydesign; - factor variables --
C(g)isi.gwith the lowest level as base;sp.marginsreports"2.g"-style discrete changes as Stata does; marginsaverages over the estimation sample (e(sample)) with the fit's weights, like Stata.
2. Two-way / high-dimensional fixed effects¶
Call: sp.feols("y ~ x | firm + year", df, cluster="state") (pyfixest
backend), sp.hdfe_ols (native, Stata reghdfe conventions),
sp.fast.feols. See panel data.
Options that matter: clustering (cluster= or vcov={"CRV1": col};
intervals use t(G - 1)); varying slopes firm + state[year] (run natively,
model_info["backend"] == "statspai-native"); weights=.
Pitfalls: with only slopes absorbed (state[[year]]) sp.feols keeps
an intercept as R fixest does, while sp.hdfe_ols / Stata reghdfe
absorb(i.state#c.year) does not.
3. Staggered policy adoption¶
Call: sp.callaway_santanna, then sp.aggte(type="dynamic"),
sp.uniform_bands, sp.honest_did. Choosing among CS / Sun-Abraham / BJS /
ETWFE: choosing a DiD estimator;
Callaway-Sant'Anna, HonestDiD.
Options that matter: control_group, base_period, anticipation,
weights, bootstrap vs analytic inference; repeated cross-sections via
panel=False (guide).
Pitfalls: a non-rejected pre-trend test is not evidence of parallel
trends -- check its power (sp.pretrends_power) and report
sp.honest_did. The joint event-study covariance behind bands and HonestDiD
is compared with R did for the default configuration
(sp.validation_scope(fit)["outputs"]["vcov"]).
4. Instrumental variables and weak instruments¶
Call: sp.iv(...), sp.effective_f_test, sp.anderson_rubin_ci;
choosing an IV estimator.
Pitfalls: switching to LIML does not fix weak-instrument inference;
report a weak-IV-robust interval. The exclusion restriction is untestable --
sp.recommend(...).identification lists it with the questions to answer.
5. Regression discontinuity (sharp, fuzzy, weighted)¶
Call: sp.rdrobust, sp.rddensity, sp.rdplot;
choosing an RD estimator.
Options that matter: weights= (observation weights, as R
rdrobust), fuzzy=, covs=, cluster=, bwselect=.
Pitfalls: check manipulation (sp.rddensity) and covariate balance at
the cutoff; validation_scope distinguishes the configurations compared
with R rdrobust from those that were not.
6. Selection on observables, matching and DML¶
Call: sp.psm / sp.match, sp.aipw, sp.dml;
choosing a matching estimator,
DML vs DoubleML.
Pitfalls: every estimator here assumes no unmeasured confounding --
check overlap (sp.overlap_plot) and sensitivity (sp.sensemakr,
sp.evalue); the recommendation's identification brief says so explicitly.
7. Survey data, calibration and multiple imputation¶
Call: sp.svydesign(...), design.calibrate(margins=... | totals=...),
sp.mice(...) then sp.mi_estimate(...) and sp.mi_test(...) for joint
tests; survey guide.
Pitfalls: calibrated weights passed to a new design are treated as fixed
-- use design.calibrate for calibration-aware standard errors (R
survey::calibrate convention by default, Stata's with
variance="stata"). Categorical variables are imputed with
'logreg' / 'polyreg'; 'sample' ignores every other variable. Joint
tests after MI are not ordinary Wald tests on the pooled covariance:
sp.mi_test is Stata's mi test, including its default small-sample df
(Reiter 2007; small=False for mi test, nosmall). With a tiny
complete-data df Reiter's df leaves its valid range: the number matches
Stata but an AssumptionWarning says not to trust it.
8. Marginal effects and predictions¶
Call: sp.margins, sp.margins_at, sp.contrast, sp.pwcompare.
Pitfalls: I(x**2) and interactions are differentiated through (the
effect of x includes 2 b2 x); a pre-computed x2 column is treated as an
independent regressor. After logit / probit / poisson the scale is Pr(y=1) /
the expected count including exposure.
9. Tables and replication¶
Call: sp.regtable(...), sp.result_card(fit),
sp.replication_pack(..., strict=True) then sp.verify_replication_pack;
replication workflow,
tables.
Pitfalls: a zip that opens is not a replication -- the verifier reruns the script in a fresh directory and compares every recorded estimate.
10. Working through an agent (MCP)¶
Call: sp.recommend(...) -- each card has ready /
missing_arguments; .identification states what the design cannot
establish. See agent-native workflow and
economist MCP workflow.
Pitfalls: a recommendation chooses a tool; it does not identify an
effect. When identification["claim"] is "descriptive_only" or a card is
blocked, the right output is a question to the user, not an estimate.