Announcement

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

  • Marginal effects for different groups using marginsplot vs eclplot

    Dear all,

    I am trying to plot marginal effects in a model with interaction terms and different groups. The easiest and fastest way is of course using -margins- and -marginsplot-. Another (much longer) way would be using -parmest- and -eclplot- (both from SSC), but then one has to compute the marginal effects and their confidence intervals by hand, build the dataset, etc.
    My problem with -margins- is that when the confidence intervals of the different groups overlap, the plot become difficult to read. To solve this issue, a nice feature of -eclplot- is the suboption -spaceby()-, which allows to add space between the parameters of different groups.
    In order to make my point clear, here is a small example:

    *******************
    *Run and store an estimation
    sysuse auto
    reg price c.mpg##c.weight##i.foreign
    estimates store reg1

    *Plot marginal effects using -margins- and -marginsplot-
    margins, dydx(mpg) at(weight=(2300(100)3000) foreign=(0/1))
    marginsplot, title("") name(marginsplot, replace)

    *Plot marginal effects using -parmest- and -eclplot- (from ssc)
    preserve
    forv w=2300(100)3000 {
    forv f=0/1 {
    restore, preserve
    est restore reg1
    nlcom _b[mpg]+_b[c.mpg#c.weight]*`w'+_b[1.foreign#c.mpg]*`f'+_b[1.foreign#c.mpg#c.weight]*`w'*`f', post level(95)
    parmest, saving(coef`w'`f', replace) // parmest from ssc
    use coef`w'`f'
    gen weight = `w'
    gen foreign = `f'
    save coef`w'`f', replace
    }
    }
    clear
    forv w=2300(100)3000 {
    forv f=0/1 {
    append using coef`w'`f'
    erase coef`w'`f'.dta
    }
    }
    *Draw the plot

    #d ;
    eclplot estimate min max weight,
    supby(foreign, spaceby(20) offset(-10))
    estopts(c(l)) ciopts(lc(gs6))
    estopts1(lc(navy) mc(navy)) estopts2(lc(maroon) mc(maroon) )
    ciopts1(lc(navy)) ciopts2(lc(maroon))
    xlab(2300(100)3000, format(%10.0gc))
    name(eclplot, replace)
    ;
    #d cr
    *******************

    You can check that both graphs are identical, the only difference being that the parameters are aligned in marginsplot while they are spaced in eclplot. In my opinion, the second one is much easier to read (even though one might argue that if confidence intervals overlap, it is not obvious that the model estimated is the optimal one I admit).

    Is there a possibility to space the parameters using -margins-?

    Thanks.



    Sylvain Weber
    University of Neuchâtel, Institute of Economic Research (irene)
    A.-L. Breguet 2, 2000 Neuchâtel, Switzerland
    +41.32.718.14.42
    [email protected]
    http://sites.google.com/site/swwebpage/

  • #2
    The code that you posted ends with an error message.
    Code:
    . eclplot estimate min max weight,
    > supby(foreign, spaceby(20) offset(-10))
    > estopts(c(l)) ciopts(lc(gs6))
    > estopts1(lc(navy) mc(navy)) estopts2(lc(maroon) mc(maroon) )
    > ciopts1(lc(navy)) ciopts2(lc(maroon))
    > xlab(2300(100)3000, format(%10.0gc))
    > name(eclplot, replace)
    > ;
    variable min not found
    r(111);
    Last edited by Friedrich Huebler; 16 Jun 2015, 07:55.

    Comment


    • #3
      This problem has long bothered me.
      while cutting and pasting is not elegant from a coding perspective--- it does allow an easier (?) approach to the problem
      1) cut and paste the output from margins into a new instance of stata (the data editor window) using the copy table command in the results window
      2) you get a new data set labelled var1- var8
      3) drop and rename variables as needed
      drop var4-var6
      rename var1 time ***x axis variable
      rename var2 subgroup *** interaction variable with x axis term
      rename var3 parameter *** parameter estimate
      rename var7 lci
      rename var8 hci
      replace time=time+.1 if subgroup==1 *** adding a small increment for each subgroup/interaction level)
      4) use eclplot
      eclplot parameter lci hci time, supby (time) eplottype(connected)

      Comment


      • #4
        Here is different solution that maybe some people better acquainted with using matrices in Stata can expand on or make more efficient. Regardless, this is the beginning of a method I have used to capture the results of -margins- without copying and pasting, that can then be visualized using whatever method you prefer.

        Best,
        Alan

        Code:
        /* Show typical kind of output from -margins- & -marginsplot-  */
        sysuse auto, clear
        regress mpg i.foreign c.weight##c.weight
        margins, at(weight=(1800(250)4500))
        marginsplot
        
        /* Save margins results as variables for visualizing */
        capture drop b1
        matrix b=r(b)'
        svmat double b
        
        capture drop at1
        capture drop at2
        capture drop at3
        matrix at=r(at)
        svmat at
        
        /* Visualize the data */
        preserve
          keep b1 at3
          keep if !missing(b1) 
          list
          graph twoway line b1 at3;
        restore
        
        /* Clean up any unneeded mess */
        capture drop b1
        capture drop at?

        Comment


        • #5
          Here is another way by extracting the data from the marginsplot graph
          Code:
          sysuse auto,clear
          qui reg price c.mpg##c.weight##i.foreign
          
          *Plot marginal effects using -margins- and -marginsplot-
          qui margins, dydx(mpg) at(weight=(2300(100)3000) foreign=(0/1))  post 
          marginsplot, title(Original Plot) name(marginsplot, replace)
          
          tempfile f1
          serset dir
          serset set 0
          serset use 
          rename (_ci_lb _ci_ub __0 _margin ) (domestic_lb domestic_ub weight domestic_margin)
          save `f1',replace
          
          serset set 1
          serset use 
          rename (_ci_lb _ci_ub __0 _margin ) (foreign_lb foreign_ub weight foreign_margin)
          
          merge 1:1 weight using `f1'
          gen w2 = weight +10
          twoway connect domestic_marg weight , mc(navy) lc(navy) /// 
           || rcap domestic_ub domestic_lb weight , lc(navy) /// 
           || connect foreign_margin w2, mc(maroon) lc(maroon) /// 
           || rcap foreign_ub foreign_lb w2 , lc(maroon) /// 
           || , legend(order(1 "Domestic"  3 "Foreign" )) /// 
            xlabel(2300(100)3000) xtitle(Weight (lbs.)) /// 
            ytitle(Effects on Linear Prediction) title(Jittered Plot)

          Comment


          • #6
            Thanks to all of you!

            My quick replies.
            • Friedrich: sorry, I wrote the code in a do-file and I used some commands (#d in particular) that do not work interactively. In order to run my code, copy-paste it in a do-file and then run the do-file.
            • Peter: indeed if we can extract what margins or marginsplot produces, then we might use it and spare quite a few lines of code. However, I'd prefer to avoid any copy-paste.
            • Alan: I'm not sure whether the solution you propose would work if we wanted to include confidence intervals.
            • Scott: That works. However, I am not acquainted with -serset- and some of your steps are quite obscure to me.

            In the meantime, I also found a way to solve the issue, using Ben Jann's -coefplot- (from ssc). Details about -coefplot- can be found in Ben Jann's paper available here: https://ideas.repec.org/p/bss/wpaper/1.html. And for what we are interested in here, see page 37 of this paper.

            So here is the new code I propose:
            Code:
            sysuse auto, clear
            reg price c.mpg##c.weight##i.foreign
            estimates store reg1
            
            margins, dydx(mpg) at(weight=(2300(100)3000) foreign=(0/1))
            marginsplot, title("Original marginsplot") name(marginsplot, replace)
            
            margins, dydx(mpg) at(weight=(2300(100)3000) foreign=0) post
            estimates store m0
            est restore reg1
            margins, dydx(mpg) at(weight=(2300(100)3000) foreign=1) post
            estimates store m1
            
            coefplot (m0, offset(-10) lab(Domestic)) (m1, offset(10) lab(Foreign)), at recast(connected) ciopts(recast(rcap)) xti("Weight") xlab(2300(100)3000, format(%10.0gc)) ti("Plot using coefplot") name(coefplot, replace)
            I think all of this solves the issue.
            Thanks again very much.

            Sylvain

            Comment


            • #7
              Sylvain,

              I didn't take the time to capture the upper and lower limits of the results of margins. But, they are available to you in the matrix r(table). COnsider the following Stata code whoch shows the contents of two matrices, r(table) and r(at). You will see the available results:

              Code:
              sysuse auto, clear
              regress mpg i.foreign c.weight##c.weight
              margins, at(weight=(1800(250)4500))
              
              return list
              matrix list r(table)
              matrix list r(at)
              And, the results are :
              Code:
              . matrix list r(table)
              
              r(table)[9,11]
                              1.         2.         3.         4.         5.         6.         7.         8.         9.
                            _at        _at        _at        _at        _at        _at        _at        _at        _at
                   b  31.207784  28.596034  26.183179  23.969217   21.95415  20.137977  18.520699  17.102315  15.882825
                  se  1.1177015  .79250393  .58648039  .50594374  .50966891  .53624429  .55517808  .57203319  .62179523
                   t  27.921395  36.083145  44.644594  47.375262  43.075318  37.553738  33.359925  29.897417  25.543497
              pvalue  1.127e-39  5.754e-47  3.590e-53  6.417e-55  4.029e-52  4.022e-48  1.038e-44  1.354e-41  3.304e-37
                  ll  28.978599  27.015435   25.01348  22.960144  20.937648  19.068472  17.413431   15.96143  14.642693
                  ul   33.43697  30.176634  27.352877   24.97829  22.970653  21.207483  19.627967  18.243199  17.122956
                  df         70         70         70         70         70         70         70         70         70
                crit  1.9944371  1.9944371  1.9944371  1.9944371  1.9944371  1.9944371  1.9944371  1.9944371  1.9944371
               eform          0          0          0          0          0          0          0          0          0
              
                             10.        11.
                            _at        _at
                   b  14.862229  14.040528
                  se  .75174899  .98894075
                   t  19.770202  14.197542
              pvalue  2.323e-30  2.711e-22
                  ll  13.362913  12.068148
                  ul  16.361545  16.012908
                  df         70         70
                crit  1.9944371  1.9944371
               eform          0          0
              
              . matrix list r(at)
              
              r(at)[11,3]
                           0b.       1.         
                      foreign  foreign   weight
               1._at        .        .     1800
               2._at        .        .     2050
               3._at        .        .     2300
               4._at        .        .     2550
               5._at        .        .     2800
               6._at        .        .     3050
               7._at        .        .     3300
               8._at        .        .     3550
               9._at        .        .     3800
              10._at        .        .     4050
              11._at        .        .     4300
              Best,
              Alan

              Comment

              Working...
              X