Announcement

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

  • Programming test for xtreg


    Dear Statalist members,

    I am learning Stata programming language and try to "replicate" Stata's xtreg model. Of course, my purpose is not to create another version of xtreg. Here is my code:

    Code:
    cap program drop myxtreg
    program define myxtreg , eclass prop( xt )
    version 14.2
        syntax varlist(numeric ts) [if] [in] [,fe re cluster(varname)]
        marksample touse
        markout `touse' `cluster', strok
        xtset `id' `time'
        tempvar id time    
        gen `id' = `r(panelvar)'
        gen `time' = `r(timevar)'
        gettoken depvar iv: varlist
        
         tempname a b  
        
        if "`fe'" != "" {
            xtreg `depvar' `iv' if `touse', fe
            matrix `a' = e(b)
            matrix `b' = e(V)
            ereturn post `a' `b', depn(`depvar') esample(`touse')
            ereturn local cmd "myxtreg"
        }
            else if "`re'" != "" {
                xtreg `depvar' `iv' if `touse', re
                matrix `a' = e(b)
                matrix `b' = e(V)
                ereturn post `a' `b', depn(`depvar') esample(`touse')
                ereturn local cmd "myxtreg"
            }
                else if "`cluster'" != "" {
                    xtreg `depvar' `iv' if `touse', vce(cluster `cluster')
                    matrix `a' = e(b)
                    matrix `b' = e(V)
                    ereturn post `a' `b', depn(`depvar') esample(`touse')
                    ereturn local cmd "myxtreg"
                }
                    else if ("`fe'" != "" & "`cluster'" != "") {
                        xtreg `depvar' `iv' if `touse', fe vce(cluster `cluster')
                        matrix `a' = e(b)
                        matrix `b' = e(V)
                        ereturn post `a' `b', depn(`depvar') esample(`touse')
                        ereturn local cmd "myxtreg"
                    }
                        else if ("`re'" != "" & "`cluster'" != "") {
                            xtreg `depvar' `iv' if `touse', re vce(cluster `cluster')
                            matrix `a' = e(b)
                            matrix `b = e(V)
                            ereturn post `a' `b', depn(`depvar') esample(`touse')
                            ereturn local cmd "myxtreg"
                        }
                            else {
                                xtreg `depvar' `iv' if `touse'
                                matrix `a' = e(b)
                                matrix `b' = e(V)
                                ereturn post `a' `b', depn(`depvar') esample(`touse')
                                ereturn local cmd "myxtreg"
                            }
                
    end

    this program works when I separately activate the option of fe, re, and cluster(). But it doesn't work when I use the option fe or re and cluster() at the same time. Thus:

    use http://www.stata-press.com/data/r14/nlswork.dta
    xtset idcode year
    myxtreg ln_wage wks_work hours tenure ttl_exp, fe // this identical with
    xtreg ln_wage wks_work hours tenure ttl_exp, fe

    myxtreg ln_wage wks_work hours tenure ttl_exp, cluster(idcode) // is identical with
    xtreg ln_wage wks_work hours tenure ttl_exp, vce(cl idcode)

    But....

    myxtreg ln_wage wks_work hours tenure ttl_exp, fe cluster( idcode) // does not yield the same result as
    xtreg ln_wage wks_work hours tenure ttl_exp, fe vce(cluster idcode)

    Can anyone help me point out my mistake in the program code? Any help is much appreciated. Thank you.



    Regards,


    Afri
    Last edited by afri afrimadona; 23 May 2018, 21:47.

  • #2
    Originally posted by afri afrimadona View Post
    this program works when I separately activate the option of fe, re, and cluster(). But it doesn't work when I use the option fe or re and cluster() at the same time.
    It's because of the logic of if-else flow control. If you put the two options in a single if-else block, then you can have one or the other program sections execute, but not both. If you want to have the option of A and B, then put them in separate (tandem) if-else blocks.

    Code:
    if fe {
    
    }
    else if re {
    
    }
    else {
    
    }
    // and then
    if cluster {
    
    }
    else {
    
    }

    Comment


    • #3
      Joseph proposes a solution; I would like to elaborate on the problem. As it stands, the following code in #1 will never be executed

      Code:
                      else if ("`fe'" != "" & "`cluster'" != "") {
                          xtreg `depvar' `iv' if `touse', fe vce(cluster `cluster')
                          matrix `a' = e(b)
                          matrix `b' = e(V)
                          ereturn post `a' `b', depn(`depvar') esample(`touse')
                          ereturn local cmd "myxtreg"
                      }
                          else if ("`re'" != "" & "`cluster'" != "") {
                              xtreg `depvar' `iv' if `touse', re vce(cluster `cluster')
                              matrix `a' = e(b)
                              matrix `b = e(V)
                              ereturn post `a' `b', depn(`depvar') esample(`touse')
                              ereturn local cmd "myxtreg"
                          }
      Joseph's proposed code is a general solution and illustrates an important concept. It will, however, not be particularly helpful much for the example in #1 as it will run the regression twice; once without the cluster option and then once again with the cluster option.

      An alternative would be spelling out each case

      Code:
      if (("`fe'" != "") & ("`cluster'" != "")) {
      
      }
      else if (("`fe'" != "") & ("`cluster'" == "") {
      
      }
      else if ... {
      
      }
      else {
          // NotReached
          // programming error
      }
      but you would not want to do this. Perhaps you would want something like

      Code:
      if ("`cluster'" != "") {
          if ("`fe'" != "") {
          
          }
          else if ("`re'" != "") {
          
          }
          else {
          
          }
      }
      else if ("`cluster'" == "") {
          if ("`fe'" != "") {
          
          }
          else if ("`re'" != "") {
          
          }
          else {
          
          }
      }
      Personally, I would probably set this up as

      Code:
      if ("`cluster'" != "") {
          local vce_cluster vce(cluster `cluster')
      }
      
      xtreg ... , `fe' `re' `vce_cluster'
      One additional problem with code in #1 is

      Code:
          xtset `id' `time'
          tempvar id time    
          gen `id' = `r(panelvar)'
          gen `time' = `r(timevar)'
      The locals id and time do not exist when they are referenced. This is not a syntax error, it just means that the first line will always be

      Code:
      xtset
      If id and time were options to be filled with variable names, it would likely not be a good idea to create temporary variables with the same names, as the locals (i.e. options) would then be overwritten with the names for the temporary variables (and vice versa). I am not clear on the intention of these lines either way, since they do not affect the rest of the code.

      Best
      Daniel
      Last edited by daniel klein; 24 May 2018, 01:12.

      Comment


      • #4
        Thanks a lot for your helpful suggestions, Joseph and Daniel. I can run the model perfectly following Daniel's suggestion (the long version). But I am curious for Daniel's personally preferred code, like

        Personally, I would probably set this up as

        Code:
        if ("`cluster'" != "") { local vce_cluster vce(cluster `cluster') } xtreg ... , `fe' `re' `vce_cluster'
        If you do not mind, could you give the full code for this, Daniel? I think the more efficient the code, the better it is. I am eager to learn more efficient and effective code for this. Thank you.


        Best regards,

        Afri

        Comment


        • #5
          Originally posted by afri afrimadona View Post
          But I am curious for Daniel's personally preferred code [...] If you do not mind, could you give the full code for this, Daniel? I think the more efficient the code, the better it is. I am eager to learn more efficient and effective code for this.
          Actually, the code in #3 is the full code, already. Well, you could (should?) be more explicit and code

          Code:
          if ("`cluster'" != "") {
              local vce_cluster vce(cluster `cluster')
          }
          else {
              local vce_cluster // void
          }
          I tend not to define empty (or void) locals when I know that I have not defined them before; when I do, I tend to make this explicit and include the

          Code:
          // void
          comment.

          I doubt that for the problem here there is any gain in efficiency of the alternative codes; my preferred code is simply less to type (and arguably more readable). The key idea is that inside the various if else conditions you have essentially the same five lines of code

          Code:
          xtreg `depvar' `iv' if `touse', re vce(cluster `cluster')
          matrix `a' = e(b)
          matrix `b' = e(V)
          ereturn post `a' `b', depn(`depvar') esample(`touse')
          ereturn local cmd "myxtreg"
          The last four of those lines are exactly the same, regardless of the options that are specified; the first line only differs in terms of three elements, fe, re, and cluster, each of which has two states: empty or not. Also two of these elements, fe and re, need not be altered, i.e., are passed thru as specified. Note that xtreg will exit with an error when both, fe and re, are specified and so I do not even bother checking here (I certainly would in longer programs or when xtreg would be the last of many tasks to perfrom). When you wanted, e.g., fe to be the default, you would need more code to ensure this here, too. Anyway, there is only one element left to take care of: cluster, which needs to be transformed to vce(cluster `cluster') when specified, i.e., not empty. You could be a bit more redundant than above and code

          Code:
          if ("`cluster'" != "") {
              xtreg ... , `fe' `re' vce(cluster `cluster')
          }
          else {
              xtreg ... , `fe' `re'
          }
          
          matrix `a' = e(b)
          matrix `b' = e(V)
          ereturn post `a' `b', depn(`depvar') esample(`touse')
          ereturn local cmd "myxtreg"
          but you would certainly not code the same last four lines multiple times. As a general rule: never re-type (essentially) the same thing; it is too likely to introduce errors and these will have to be fixed in multiple places, too.

          Before you think about efficiency (in terms of coding [and execution]) think about readability and error-proneness of your code; sometimes those concepts coincide. I encourage you to read Nick Cox (2005) excellent article on programming style in Stata.

          Best
          Daniel

          Cox, N. J. 2005. Suggestions on Stata programming style. The Stata Journal, 5(4), pp. 560-566.
          https://www.stata-journal.com/sjpdf....iclenum=pr0018
          Last edited by daniel klein; 24 May 2018, 23:12.

          Comment


          • #6
            Thank you a lot, Daniel. Yes, your last code is more readable, simple and efficient. I can run it perfectly like the previous one (the long version). Your suggestions are very helpful. Thank you again for helping me learn this program.

            Comment

            Working...
            X