Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Compatibility issue between f_able/f_rcspline and did2s in Stata

    I am experiencing what seems to be a compatibility issue between the user-written packages f_able (f_rcspline) and did2s in Stata 18 (both installed from SSC).

    When generating natural spline basis variables with f_rcspline and including them in the second stage of did2s, I receive the following error:

    "command double is unrecognized"

    Example code:

    f_rcspline alderpaaselskapet = alderpaaselskapet, nknots(4)

    did2s lnopa, first_stage(org regnskapsår) ///
    second_stage(c.l_D_oppslag##c.l_D_kurs##c.l_D_over sikt ///
    c.l_D_oppslag#c.alderpaaselskapet ///
    c.l_D_oppslag#c.alderpaaselskapet2 ///
    c.l_D_oppslag#c.alderpaaselskapet3) ///
    treatment(l_D) cluster(org)

    margins, dydx(c.l_D_oppslag c.l_D_kurs c.l_D_oversikt)

    f_able alderpaaselskapet2 alderpaaselskapet3, auto

    margins, dydx(c.l_D_oppslag) at(alderpaaselskapet = (0(15)126))

    This workflow runs as expected using xtreg but fails with did2s.

    Is this a known limitation of either package? Are there workarounds for using spline basis variables with did2s?

    Any advice appreciated.

    Emil Mathias Strøm Halseth

  • #2
    I think that is a did2s problem
    keep in mind margins works if there is a predict function behind the estimation method
    If that doesnt exist then margins and f_able will have issues working

    Comment


    • #3
      Thanks for the reply!

      I should say, that margins ostensibly works with did2s. I only have problems with the f_able part. For example, this code (the first part):

      did2s lnopa, first_stage(org regnskapsår) ///
      second_stage(c.l_D_oppslag##c.l_D_kurs##c.l_D_over sikt ///
      c.l_D_oppslag#c.alderpaaselskapet ///
      c.l_D_oppslag#c.alderpaaselskapet2 ///
      c.l_D_oppslag#c.alderpaaselskapet3) ///
      treatment(l_D) cluster(org)

      margins, dydx(c.l_D_oppslag c.l_D_kurs c.l_D_oversikt)

      works fine. At least the margins command produces numbers that seem reasonable. I, of course, do not know exactly what goes on under the hood to produce those numbers. But I speculate that the second stage of the did2s procedure is what is left in SATA's memory, which is a simple regression on residualized observations. I suppose a predict operation can, and is, performed on that regression.

      Comment


      • #4
        In that case I may need an example. And your Stata version
        it may be a simple case of command specific

        Comment


        • #5
          Apologies for the late reply, I don't seem to get notifications.

          My STATA-version is StataNow 19 SE.

          What kind of example would you need?

          Comment


          • #6
            any replicable example. I may be able to back track it from there

            Comment


            • #7
              I see. I suppose I could use some standard dataset available through STATA? When you say replicable you do mean that you need to be able to run the code on data?

              Comment


              • #8
                Here is a do-file that reproduces the issue on sample data from Stata, with artificial treatment variables:

                * Reproducible DiD2S + margins + f_able example
                clear all
                set more off

                * 0) Data: The nlswork data to get some panel data to work with
                webuse nlswork, clear
                xtset idcode year

                * 1) Randomly keep ~30% of idcodes, but keep all their years. Reduces computation.
                set seed 123456
                tempfile keepids
                preserve
                keep idcode
                duplicates drop
                gen double u = runiform()
                keep if u < 0.30
                save `keepids'
                restore
                merge m:1 idcode using `keepids', keep(match) nogen

                * 2) Construct staggered treatment timing (deterministic by id)
                * ~30% treated from 1972, ~30% from 1980, ~10% from 1985, rest never treated
                gen treat_year = .
                replace treat_year = 72 if inrange(mod(idcode,10),0,2)
                replace treat_year = 80 if inrange(mod(idcode,10),3,5)
                replace treat_year = 85 if mod(idcode,10)==6
                label var treat_year "First treated year (.) = never treated"

                * 3) Time-varying treatment indicator
                gen D = (year >= treat_year) if treat_year < .
                replace D = 0 if missing(D)
                label var D "Treated in year t"

                * 4) did2s (baseline without interactions)
                did2s ln_wage, ///
                first_stage(i.idcode i.year) ///
                second_stage(i.D) ///
                treatment(D) ///
                cluster(idcode)

                * 5) Marginal effect of turning treatment on (ATE on residualized outcome)
                margins, dydx(D)

                ***** This works fine, and margins produces the expected number *****

                * 6) Build a restricted cubic spline basis for age (4 knots)
                * This creates: age (linear term) plus age2 and age3 as nonlinear bases
                f_rcspline age = age, nknots(4)

                ***** This should allow a nonlinear relation between the treatment effect and age (nonlinear marginsplot) *****

                * 7) did2s with nonlinear interaction: D × rcs(age)
                did2s ln_wage, ///
                first_stage(i.idcode i.year) ///
                second_stage(c.D c.D#c.age c.D#c.age2 c.D#c.age3) ///
                treatment(D) ///
                cluster(idcode)

                * 8) Average discrete effect of turning D on (ATE on residualized outcome)
                margins, dydx(D)

                ***** Again, the number returned by margins is reasonable. I assume did2s works as expected with margins *****

                * 9) Tell margins how to vary transformed terms with age
                * (lets margins change age and automatically adjust age2/age3)
                f_able age2 age3, auto

                * 10) Marginal effect of turning D on, by age (15 to 40 by 5)
                margins, dydx(D) at(age = (15(5)40))


                The final margins command yields:

                warning: cannot perform check for estimable functions.
                command double is unrecognized


                Note: If you don't run f_able, margins, dydx(D) at(age = (15(5)40)) runs but produces a linear relation between treatment and age, as expected.

                Comment


                • #9
                  Its an error in did2s.
                  you need to do the following

                  run program

                  program adde, eclass
                  ereturn `0'
                  end

                  then type
                  adde local predict_old _predict

                  then run margins.

                  Comment


                  • #10
                    That works! Awesome.

                    Thank you so much.

                    Comment


                    • #11
                      Curious why you’re using did2s. Fernando’s jwdid does the regression in one step and will show you the moderating effects and their standard errors. Plus, it interacts the age cohort dummies with time dummies to relax parallel trends.

                      Comment


                      • #12
                        Curious why you’re using did2s. Fernando’s jwdid does the regression in one step and will show you the moderating effects and their standard errors. Plus, it interacts the age cohort dummies with time dummies to relax parallel trends.

                        Comment


                        • #13
                          The short answer is that I (technically) know how to apply did2s in my “complicated” research setup. I have not yet used jwdid, although I recently started looking into it because of the option to use Logit and Poisson methods.

                          My research setting is as follows: I want to evaluate the benefits of using three different products on firm outcomes. I have a panel of firms observed over multiple years. In the data, firms may use any combination of the three products (i.e. seven possible indicators), and in some cases they opt out. This means there are multiple treatments as well as both switchers-in and switchers-out.

                          What I don’t know is how to define the cohort dummies (first time treated) required for methods such as csdid and jwdid, or whether there is even a meaningful way to do so. The combination of multiple treatments and switching out is what throws me off.

                          did2s has the practical benefit of accepting the treatment indicators directly in stage 2. Hopefully this accounts for treatment heterogeneity, although the way I use it, I am implicitly assuming complete treatment reversal after switching out.

                          Can jwdid be appropriately applied in my setting?

                          Comment


                          • #14
                            Yes, that's a complicated setting. Mechanically, imputation approaches allow complicated patterns, but I don't think they work for general patterns. Some time ago I did simulations of the BJS imputation estimator with exit, and it was badly biased. A current student of mine are proposing a method that allows switching on and off, and can accommodate multiple treatment levels. Unfortunately, no paper yet.

                            Comment


                            • #15
                              I’ll keep your simulation results in mind!

                              Would that bias still be present if (big if!) treatment effects were completely reversed after exit? My intuition is that in such a case, untreated observations after exit would be viable controls for imputing the counterfactuals of treated units, just as untreated observations before entry are.

                              Best of luck to your student! It would be very cool, and useful, to have an estimator that can identify treatment effects in a more general setting.

                              Comment

                              Working...
                              X