*! version 30aug2024

Partially-linear model - Detailed general example with multiple learners

Here we used ddml to add learners. This allows use of learners not supported by,
or as alternatives to, those available via pystacked.
It is also possible to use pystacked as a standalone learner in this way.

Preparation: load the data and define the globals.
Use the name "m1" for this new estimation,
to distinguish it from any model estimated previously that uses the default name "m0".
This enables having multiple estimations available for comparison.
We also use the prefix option of ddml init
so that all the estimated conditional expectations will be prefixed with the model name,
i.e., the names of all created variables will start with "m1".
This avoids overwriting any variables created for some other model using default naming.
Also specify 5 resamplings.

. use https://github.com/aahrens1/ddml/raw/master/data/sipp1991.dta, clear

. global Y net_tfa

. global D e401

. global X tw age inc fsize educ db marr twoearn pira hown

. set seed 42

. ddml init partial, kfolds(2) reps(5) mname(m1) prefix

We add supervised machine learners for estimating the conditional expectation E[Y|X].
In each step, we add the mname(m1) option to ensure that the learners are added to correct model.

We first add simple linear regression.

. ddml E[Y|X], mname(m1): reg $Y $X

We can add more than one learner per reduced form equation.
Here, we add a random forest learner.
We do this using pystacked to implement a single learner.

. ddml E[Y|X], mname(m1): pystacked $Y $X, type(reg) method(rf)

We do the same for the conditional expectation E[D|X].

. ddml E[D|X], mname(m1): reg $D $X

. ddml E[D|X], mname(m1): pystacked $D $X, type(reg) method(rf)

Check if learners were correctly added:

. ddml desc, mname(m1) learners

Cross-fitting and estimation.
Since we added two learners for each of our two reduced form equations,
there are four possible specifications.
By default, the result shown corresponds to the specification
with the lowest out-of-sample MSPE:

. ddml crossfit, mname(m1)

. ddml estimate, mname(m1) robust

To estimate all four specifications, we use the allcombos option:

. ddml estimate, mname(m1) robust allcombos

After having estimated all specifications, we can retrieve
specific results. Here we use the specification relying on OLS for both
estimating both E[Y|X] and E[D|X], from the 4th cross-fit split (rep(4)).
(Note: Working interactively, the simplest way to do this
is to click on the hyperlink in the summary table in the ddml estimate output above.)
The notable option suppresses the summary table:

. ddml estimate, mname(m1) spec(1) rep(4) replay notable

You could manually retrieve the same point estimate by
cacluating the orthogonalized versions of net_tfa and e401
from the 4th cross-fit estimation and then using regress.
Recall that we used the prefix option with ddml init,
so the variable names start with "m1".

. cap drop Yresid

. cap drop Dresid

. gen double Yresid = $Y - m1_Y1_reg_4

. gen double Dresid = $D - m1_D1_reg_4

. regress Yresid Dresid, robust

You can also compare the estimated conditional expectations graphically:

. twoway (scatter $Y m1_Y2_pystacked_4)

To describe the ddml model setup or results in detail,
you can use ddml describe with the relevant option (sample, learners, crossfit, estimates),
or just describe them all with the all option:

. ddml describe, mname(m1) all

If there is a previously-estimated ddml model called "m0",
we can load it using ddml estimate with the mname(m0) and replay options and compare.

. ddml estimate, mname(m0) replay