Announcement

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

  • Errors using quotes and global macros in a loop

    For context, I am attempting to conduct a moderated mediation analysis in Stata ala https://stats.oarc.ucla.edu/stata/faq/how-can-i-do-moderated-mediation-in-stata/. As part of the procedures to estimate indirect effects, I eventually will be multiplying the coefficient of a predictor on the outcome with the coefficient of a predictor on a mediator. Because I will have multiple predictor variables, mediators, and moderators I would like to copy regression coefficients from separate regressions into global macros generated in a do foreach loop so that I can refer to them with mnemonic names, However, I am referring to the content of the global macros incorrectly in the loop.

    Here is a fragment of a program that is supposed to generate the global macros and display the macro name and it's content.

    Code:
    . global objective interval length  
    . capture program drop boottest
    
    . program boottest, rclass
      1.     quietly xtreg emopos $objective, fe 
      2.         
    .         foreach var of varlist  $objective   {
      3.                 return scalar  pos_`var'_d = _b[`var']
      4.                 global pos_`var'_d = _b[`var']
      5.                 di "pos_`var'_d", $pos_`var'_d
      6.                 }
      7. end
    macro list shows that the global macros were saved correctly
    Code:
    . macro list
    pos_length_d:   .0191397788464435
    pos_interval_d: .0204940257696814
    However, When I run the program, I am getting a macro not found error because I am referring to it incorrectly in the loop.
    Code:
    . boottest
    pos_interval_d interval_d not found
    I must be using quotes incorrectly. in the portion of the loop where I attempt to refer to the content of the global macro "$pos_`var'_d". The "pos_ portion of the macro name is dropped and I get the interval_d not found error. I've read the documentation on using single and double quotes and Nick Cox's tutorials on this, but clearly am not understanding. I'd appreciate any help.

  • #2
    It looks to me like Stata doesn't know how to insert the local macro into the global macro name, so $pos_ is interpreted as the global macro name ($pos_ isn't assigned to, so it resolves to the empty string). Does pos_`var'_d need to be a global macro? You already pass the value out by returning it, so you shouldn't need to globalize the macro to access the data at a higher scope. I convert it to a local and the following seems to work correctly for me:

    Code:
    clear
    input int(time id emopos interval length)
    1 1 1 0 9
    1 2 2 1 8
    1 3 3 2 7
    2 1 2 3 6
    2 2 1 4 5
    2 3 4 5 4
    3 1 5 6 3
    3 2 6 7 2
    3 3 5 8 1
    end
    
    xtset id time
    
    global objective interval length  
    capture program drop boottest
    
    program boottest, rclass
         quietly xtreg emopos $objective, fe
            
         foreach var of varlist $objective {
                     return scalar  pos_`var'_d = _b[`var']
                     local pos_`var'_d = _b[`var']
                     di "pos_`var'_d", "`pos_`var'_d'"
                     }
    end
    
    boottest
    As a bit of an aside, are you sure you need globals here at all? I notice you use $objective to pass data directly into your boottest program, circumventing the usual syntax command. I can understand wanting to have a shorthand for things at a higher scope, but I would still almost always prefer locals for this, and using globals to pass data into a program breaks scope entirely. Scope is your friend, and it seems like you might run into complexity and scaling issues doing things this way. Besides, the global syntax sometimes behaves in unexpected ways, as illustrated by your post.

    Why not write the boottest program so that it accepts $objective as an argument, with syntax like this:

    Code:
    boottest $objective
    For the sake of generalizability, you might also want to pass in emopos rather than referring to it directly in the program, but that's a whole other conversation.

    Comment


    • #3
      I am not a big fan of globals, but any way I think the problem in #1 is that you need to ensure that a local macro is evaluated first. The syntax to do that is to use braces

      Code:
      ${pos_`var'_d} 
      as documented at https://www.stata.com/manuals/u18.pdf 18.3.10.

      Otherwise Stata sees

      Code:
      $pos_
      and doesn't know what that means, and substitutes nothing. So far, so good. Then it sees

      Code:
      `var'_d
      and evaluates that as

      Code:
      interval_d
      Now it has a problem. You're asking, it thinks, to display that, but it is evidently neither a variable name nor a scalar name; hence your error message.

      Comment


      • #4
        Thank you both so much. You are correct that I don't need global macros for my application. I had misunderstood the scope of local macros, thinking their scope was the do loop in which they were defined rather than the encompassing do program

        Comment

        Working...
        X