Announcement

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

  • jwdid: DID using ETwFE

    Dear all
    thanks to prof. Baum a new command is ready to use.
    jwdid implements the did estimator proposed by prof Wooldridge. It also includes a simple post estimation command to allow easy estimation of ATTs .
    the syntax is similar to csdid, so you may want to use it as a robustness check
    let me know if you have questions
    Fernando

  • #2
    Dear Fernando, many thanks for the great contribution. I worked on the case of balanced panel and everything seems good. Just wondering if the model is adjusted for unbalanced panel data if group FEs instead of individual FEs are included (Section 9 of Wooldridge (2021)).

    There are several tiny typos in the help file:
    1. "...one should simply use a full cted set of dummies allowing for..."
    2. "...the methodology proposed by Prof. Wooldridge has mportant advantages over other methods..."
    3. The error terms in the two linear equations should be "e_it".

    Comment


    • #3
      Fei Wang Thank you
      i ll make those changes in future update
      and regarding unbalanced panels. My first answer would be yes it should. But I don’t have any dataset at hand to check how would it work in that case.
      I ll go over some of prof Wooldridge examples for unbalanced panels and see what we get
      Fernando

      Comment


      • #4
        Below please find an unbalanced panel data example for manipulation.

        Code:
        webuse nlswork, clear
        
        * Create a treatment indicator: Ever joined the union
            bys idcode (year): gen w = cond(sum(union)<1,0,1)
        
        * Keep needed variables
            keep idcode year w ln_wage
            
        * Generate first_treat and keep a small subsample
            bys idcode (year): egen first_treat = total(year*(w&!w[_n-1]))
            keep if first_treat <= 72    //first_treat = 0, 70, 71, and 72
            keep if year <= 72    //year = 68, 69, 70, 71, and 72
            
        * Estimation using jwdid: Regression 1 (individual FEs)
            jwdid ln_wage, ivar(idcode) tvar(year) gvar(first_treat)
        
        * Replication of regression 1 using reghdfe
            reghdfe ln_wage i(70/72).first_treat#year#1.w, a(idcode year) vce(cluster idcode) noempty keepsin
                
        * Estimation using jwdid: Regression 2 (group FEs, coefficients different from regression 1)
            jwdid ln_wage, ivar(idcode) tvar(year) gvar(first_treat) group
        
        * Replication of regression 2 using reghdfe
            reghdfe ln_wage i(70/72).first_treat#year#1.w, a(first_treat year) vce(cluster idcode) noempty keepsin
            
        * Correction to regession 2: Coefficients identical to regression 1
            forvalues y = 69/72 {
                bys idcode: egen year`y' = mean(`y'.year)
            }  
            reghdfe ln_wage i(70/72).first_treat#year#1.w 70.first_treat#c.(year70-year72) 71.first_treat#c.(year71-year72) 72.first_treat#c.year72 year69-year72, a(first_treat year) vce(cluster idcode) noempty keepsin

        Comment


        • #5
          Thank you!
          So you are correct. I may circle back on the next update on adding that option. While i don't think that will be important for the linear case (since one can just drop the "group" option, it may be more important for the nonlinear cases (poisson logit etc).
          On the other hand. I wonder if it makes sense to have to results that do not necessarily match. Specifically, if one has repeated crossection, you are expected to see different results.
          Anyways, i will check back on the paper, and add this in.
          Thanks again
          Fernando

          Comment


          • #6
            Yes, Fernando, the adjustment for unbalanced panel data is more useful in nonlinear models for the purpose of avoiding the incidental parameter problem. I think Wooldridge's approach can flexibly be extended to repeated cross-sectional data where including the group FEs is the only option and there is no such adjustment as in the last part of #4. Thank you for the contribution to the Stata users who've been struggling with the rapidly growing literature of DiD.

            Comment


            • #7
              Hi Fei Wang,
              Went over the code, and have a new version. Basically it will apply the correction you mention when data is unbalanced. But, if one wants to run a repeated crossection version approach, it is possible to do so by adding the "nocorr" option.
              I think that would also apply when covariates are time-varying, but didn't include that here.
              Please take a look and let me know what you think.
              Fernando
              Attached Files

              Comment


              • #8
                Dear Fernando, thanks for the update. I checked with a more complicated unbalanced dataset and it worked perfectly when there are no covariates. The "nocorr" option worked well, too.

                When there are (time-invariant) covariates, the adjustment seems incomplete in the updated code. The adjustment for years will not only appear in group*year and year dummies themselves, but should also show up in group*year*covariates and year*covariates. Below please find an example. Please note that in the correction the covariate is uncentered so that only the coefficients of group*year*covariate are adjusted.

                Code:
                webuse nlswork, clear
                
                * Create a treatment indicator: Ever joined the union
                    bys idcode (year): gen w = cond(sum(union)<1,0,1)
                
                * Keep needed variables
                    keep idcode year w ln_wage grade
                    
                * Generate first_treat and keep a small subsample
                    bys idcode (year): egen first_treat = total(year*(w&!w[_n-1]))
                    keep if first_treat <= 72    //first_treat = 0, 70, 71, and 72
                    keep if year <= 72    //year = 68, 69, 70, 71, and 72
                    
                * Estimation using jwdid: Regression 1 (individual FEs)
                    jwdid ln_wage grade, ivar(idcode) tvar(year) gvar(first_treat)
                
                * Estimation using jwdid: Regression 2 (group FEs, coefficients different from regression 1)
                    jwdid ln_wage grade, ivar(idcode) tvar(year) gvar(first_treat) group
                
                * Correction to regession 2: Covariates uncentered
                * Coefficients of group*year*covariates are identical to regression 1
                    forvalues y = 69/72 {
                        bys idcode: egen year`y' = mean(`y'.year)
                    }  
                    reghdfe ln_wage i(70/72).first_treat#year#1.w i(70/72).first_treat#year#1.w#c.grade i(70/72).first_treat#c.grade i(69/72)year#c.grade (70.first_treat#c.(year70-year72) 71.first_treat#c.(year71-year72) 72.first_treat#c.year72 c.(year69-year72))##c.grade, a(first_treat year) vce(cluster idcode) noempty keepsin
                Another issue pops up when I checked the unbalanced case with covariates. It seems that the covariates are centered using an overall average in jwdid. As the DiD effect is naturally an ATT, the covariates are usually centered using the average on the treated (see Wooldridge (2021), Eqs (5.6), (5.7), (6.30) and (6.34)). Of course, the choice of average won't affect the effects of group*year*covariates, and the only differences appear in the standalone coefficients of group*year.
                Last edited by Fei Wang; 19 Aug 2022, 00:41.

                Comment


                • #9
                  Hi ! FernandoRios and Jeff Wooldridge, thanks for putting this up.
                  I tried to replicate Jeff Wooldridge STATA (.do) file, it was a great learning resource. However, "jwdid" gives different estimates than those in Jeff Wooldridge STATA (.do) file.
                  Let me briefly explain the data structure and what i did case-by-case.
                  The data is a balanced panel from 2011-2016.

                  w - is a post-treatment dummy, i.e, w=1 (when the unit first receives the treatment) for all the post-treatment years and 0 before.

                  f11, f12, f13, f14, f15, f16 - are year dummies respectively.

                  wsum - the number of years a unit was in treatment, therefore wsum=3 for units who were in treatment for 3 years (units who first got treatment in 2014); wsum=2 for units who were in treatment for 2 years (units who first got treatment in 2015); and finally wsum=1 for units who were in treatment for 1 years (units who treatment in 2016);

                  d4, d5, d6 are cohort dummies. Therefore, d4=1 if wsum =3 (i.e, it is the cohort who were treated in 2014); d5=1 if wsum =2 (i.e, it is the cohort who were treated in 2015); and d6=1 if wsum =1 (i.e, it is the cohort who were treated in 2016)
                  dinf - units who were never treated in the sample period

                  CASE-A: POLS estimator without covariates

                  I run the following codes to estimate treatment effects that vary by entry-cohort and time-period

                  Code:
                  reg logy c.d4#c.f14 c.d4#c.f15 c.d4#c.f16 ///      POLS Estimate (FE and RE produce similar results)
                      c.d5#c.f15 c.d5#c.f16 ///
                      c.d6#c.f16 ///
                      d4 d5 d6 i.year, vce(cluster id)
                  I interpret the post-treatment dynamic effects as:

                  c.d4#c.f14 (this gives instantaneous treatment effect (TE) for the group treated in 2014 in 2014) ; c.d4#c.f15 (TE for the same group after 1 year); c.d4#c.f16 (TE for the same group 2 years after the treatment).
                  c.d5#c.f15 (this gives instantaneous treatment effect TE for the group treated in 2015 in 2015); c.d5#c.f16 (TE for the same group after 1 year).
                  c.d6#c.f16 (this gives instantaneous treatment effect TE for the group treated in 2016 in 2016)

                  A1) Further, to estimate the TE's averaged across all post-treatment periods in each cohort, i run the following codes after POLS estimator

                  Code:
                  lincom (c.d4#c.f14 + c.d4#c.f15 + c.d4#c.f16)/3                     // average TE for cohort d4 across all post-treatment periods
                  lincom (c.d5#c.f15 + c.d5#c.f16)/2                                    // average TE for cohort d5 across all post-treatment periods
                  lincom (c.d6#c.f16)/1                                                 // average TE for cohort d6 across all post-treatment periods
                  Instead of using lincom(varlist), i can obtain same TEs averaged across all post-treatment periods in each cohort by running the following POLS:

                  Code:
                  reg logy c.w#c.d4 c.w#c.d5 c.w#c.d6 ///
                      i.year d4 d5 d6, vce(cluster id)
                  A2) Treatment intensities or event-study type estimates

                  To obtain the treatment effects (TE's) at different lengths of exposure to treatment effects, i ran the following fixed effect estimator that uses unit fixed effects instead of group fixed effects as in POLS:
                  Code:
                  gen intens1 = d4*f14 + d5*f15 + d6*f16
                  gen intens2 = d4*f15 + d5*f16
                  gen intens3 = d4*f16
                  xtreg logy intens1 intens2 intens3 i.year, fe vce(cluster id)
                  I call these coefficients as event-study type estimates, that is:
                  intens1 gives average TE at the year of treatment across all groups (instantaneous)
                  intens2 gives average TE after 1 year of tretment across all groups
                  intens3 gives average TE after 2 years of tretment across all groups

                  I hope my interpretation of coefficients is correct and i am doing it right ? Please let me know, if otherwise.

                  CASE-B: "jwdid" without covariates

                  I tried executing the "jwdid" in the same setting as above by running the following code:

                  B1) Comparison not-yet

                  Code:
                  gen first_treat = .
                      replace first_treat = 2014 if d4
                      replace first_treat = 2015 if d5
                      replace first_treat = 2016 if d6
                  
                      jwdid logy, ivar(id) tvar(year) gvar(first_treat)
                      estat group
                      estat event
                  B1) Comparison never-treated

                  Code:
                  gen first_treat = .
                      replace first_treat = 2014 if d4
                      replace first_treat = 2015 if d5
                      replace first_treat = 2016 if d6
                  
                      jwdid logy, ivar(id) tvar(year) gvar(first_treat) never
                      estat group
                      estat event
                  I want to ask the following questions

                  1. The "jwdid" (Case-B ) does not calculate all the possible TE's some are omitted, while such is not the case using Jeff Wooldridge codes (Case-A)
                  2. The treatment effects (partial aggregates) in each cohort for each period are different in Case-A and Case-B
                  3. The event and group (cohort) specific aggregate treatment effects are also different.
                  4. When i use time-invariant covariate (x1) and run the POLS after cenetring the covariate with proper margins command
                  Code:
                      sum x1 if d4
                      gen x1_dm4 = x1 - r(mean)
                      sum x1 if d5
                      gen x1_dm5 = x1 - r(mean)
                      sum x1 if d6
                      gen x1_dm6 = x1 - r(mean)
                  
                      reg logy c.w#c.d4#c.f14 c.w#c.d4#c.f15 c.w#c.d4#c.f16 ///
                      c.w#c.d5#c.f15 c.w#c.d5#c.f16 ///
                      c.w#c.d6#c.f16 ///
                      c.w#c.d4#c.f14#c.x1_dm4 c.w#c.d4#c.f15#c.x1_dm4 c.w#c.d4#c.f16#c.x1_dm4 ///             POLS Estimator
                      c.w#c.d5#c.f15#c.x1_dm5 c.w#c.d5#c.f16#c.x1_dm5 ///
                      c.w#c.d6#c.f16#c.x1_dm6 ///
                      d4 d5 d6 x1 c.d4#c.x1 c.d5#c.x1 c.d6#c.x1 ///
                      i.year i.year#c.x1, vce(cluster id)
                  The results are different when i use "jwdid" first with not-yet and then with never as comparison, respectively.
                  Code:
                   jwdid logy x1, ivar(id) tvar(year) gvar(first_treat)  // not-yet as comparison 
                  
                      estat simple
                      estat calendar
                      estat group
                      estat event
                  
                  jwdid logy x1, ivar(id) tvar(year) gvar(first_treat) never  // never-treated as comparison 
                  
                      estat simple
                      estat calendar
                      estat group
                      estat event
                  Please get back to me, why we get different coefficients on treatment effects between Jeff Wooldridge codes and "jwdid", I shall be very thankful to you. I am sorry if my interpretation of coefficients or codes i am writing is wrong. Please correct me if so.

                  Sorry for being so long in asking my question.

                  Thanks for reading.
                  Regards
                  (Ridwan)

                  Comment


                  • #10
                    Hi Ridwan
                    there is lots of information here.
                    Can you send me an email with the data you have, and the code?
                    So far the only thing that stands out to me is how you are defining first_treat
                    Code:
                    gen first_treat = .
                        replace first_treat = 2014 if d4
                        replace first_treat = 2015 if d5
                        replace first_treat = 2016 if d6
                    Seems that there is no "never treated" group. Is that the case? or am I missing something?
                    F

                    Comment


                    • #11
                      Thanks FernandoRios , Please check your email.
                      Just to clarify, dinf is the never-treated group in this data

                      (Ridwan)

                      Comment


                      • #12
                        Hi Fernando,

                        Is there a way to test parallel trend assumption (for nonlinear model) in jwdid?

                        Thanks,
                        Jongeun

                        Comment


                        • #13
                          Only if you use the option never
                          when you do that it will provide you with atts for before treatment
                          then
                          if you do estat event, post
                          yoi can test for the parallel test assumption

                          Comment


                          • #14
                            Thank you FernandoRios
                            The package is so complete and exactly what I need for my repeated cross-sectional data with time varying policy and dichotomous outcome variable. I only have a few questions:
                            Here, at your github page, you mention:
                            The caveat, you should only use time constant variables!
                            Is there a way around this? My question is in a way that I should control for a lot of variables (from continuous to polychotomous, to time varying)
                            My other question is if there is a way to test pre-trends for dichotomous variables and a logit method, either using jwdid or any other code. (I might need to ask this second one in another topic. Only I thought it might be a good option to add to jwdid if it is not yet)

                            Comment


                            • #15
                              Hi Sharnaz
                              so couple of points
                              1. The restriction to time constant variables comes from the theory. You want to avoid using time varying covariates, because they may introduce bias on the estimation of the ATT
                              However, with repeated crossection you ARE using time varying covariates anyways. You do need to assume they are stationary or time constant tho
                              2. one way for pretrend analysis would be using "never" as control, and "estat event, predict(xb)" since the idea is to test if the latent variable exihibits PTA not the Actual predicted probability.

                              I have not come up with an easy way to do this when "notyet" are used as controls. Its probably already there in Prof Wooldridge paper, I just haven't got around to implementing it.
                              F

                              Comment

                              Working...
                              X