Announcement

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

  • How to use macros using -if- conditions?

    I have the following data structure (variables):

    a aa b bb c cc d dd

    I define two macros:
    global macro1 a b c d
    global macro2 aa bb cc dd

    I can easily generate the sum of certain variables using the command:

    egen var=rowtotal($macro1)

    How can I apply -if- conditions using the command above and the macro2 in the sense that

    egen var=rowtotal($macro1) if $macro2==1

    i.e. if aa==1 or bb==1 or cc==1 or dd==1

    i.e. take the rowsum of every variable in $macro1 if the corresponding variable in $macro2 equals 1 (take the sum of a if aa==1 and b if bb==1 etc).

    Thanks for your help.

  • #2
    Your question is ambiguous as the wording

    take the rowsum of every variable in $macro1 if the corresponding variable in $macro2 equals 1

    does not uniquely match the example

    take the sum of a if aa==1 and b if bb==1 etc.

    One interpretation is this:

    1. egen is not needed here, as in each case you want the row total of precisely one variable, which is that variable. Which variable depends on something else.

    Code:
    gen var =  cond(aa == 1, a, cond(bb == 1, b, cond(cc == 1, c, cond(dd == 1, d, .))))
    is one solution. I suspect many experienced users would prefer to use a loop:

    Code:
    gen var = . 
    
    foreach v in a b c d { 
         replace var = `v' if `v'`v' == 1 
    }
    2. Another interpretation is this

    Code:
    gen var =  cond(aa == 1, a, 0) + cond(bb == 1, b, 0) + cond(cc == 1, c, 0) + cond(dd == 1, d, 0)
    except that that invites rewriting as

    Code:
    gen var =  (aa == 1) *  a  +  (bb == 1) *  b  + (cc == 1) *  c + (dd == 1) *  d
    and again a loop is possible. I'd put my guess on this one.

    Note that the use of global macros is entirely dispensable here and indeed generally. Nothing tested here.

    Comment


    • #3
      The wording is indeed ambiguous (although it may be clearer knowing that e.g. variable a and aa are related). Your solution number 2 is what I looked for. However, how does the solution look like 1) having a loop and 2) an infinite number of "related" variables (i.e. plus e ee, f ff, g gg, h hh, i ii, j jj and so on)? This means it is generally not possible to write down the conditions for each variable like in the example.

      Comment


      • #4
        Something like this is perhaps what Nick Cox has in mind.
        Code:
        * Example generated by -dataex-. To install: ssc install dataex
        clear
        input int (cat moose dog squirrel llama alpaca)
        10 1 20 0 30 0
        10 0 20 1 30 0
        10 0 20 0 30 1
        10 1 20 0 30 1
        end
        
        local a cat dog llama
        local aa moose squirrel alpaca
        local n : word count `a'
        generate total = 0
        forvalues i = 1/`n' {
            replace total = total + `: word `i' of `a'' if `: word `i' of `aa''==1
            }
        list, clean noobs
        Code:
        . list, clean noobs
        
            cat   moose   dog   squirrel   llama   alpaca   total  
             10       1    20          0      30        0      10  
             10       0    20          1      30        0      20  
             10       0    20          0      30        1      30  
             10       1    20          0      30        1      40

        Comment


        • #5
          Here's another (slightly different) way to tackle William's example:

          Code:
          * Example generated by -dataex-. To install: ssc install dataex
          clear
          input int (cat moose dog squirrel llama alpaca)
          10 1 20 0 30 0
          10 0 20 1 30 0
          10 0 20 0 30 1
          10 1 20 0 30 1
          end
          
          local a cat dog llama
          local aa moose squirrel alpaca
          local n : word count `a'
          generate total = 0
          forvalues i = 1/`n' {
              gettoken A a : a 
              gettoken AA aa : aa 
              replace total = total + `A' if `AA'==1
          }
          list, clean noobs

          Comment


          • #6
            This is it. Thank you. However, I have so many variables with the same prefix that I want to use in the local macro that I cannot manually include. I use the following command:

            local a var*
            local aa var*

            This however doesn't seems to work. The problem must be with the definition of the local macro. How can I define the local macro using the above type of varlist (i.e. var*)?

            Comment


            • #7
              You need

              Code:
              unab a : var* 
              and so forth. All your use of local here does is copy the text such as "var*" literally. It won't evaluate, parse or unpack a varlist wildcard into a list of variable names. That's what unab does.

              To see the effects of local definition, I usually issue

              Code:
              mac list
              I necessarily get shown some stuff that's irrelevant to the present purpose, but positively also a convenient list of whatever macros are presently defined.

              Comment


              • #8
                Many thanks! In addition to the rowsum, how can I count the number of observations for which the above condition holds? Using the "count" command doesn't seem to work:

                local a cat dog llama
                local aa moose squirrel alpaca
                local n : word count `a'
                generate total_obs = 0
                forvalues i = 1/`n' {
                replace total_obs = total_obs + count `: word `i' of `a'' if `: word `i' of `aa''==1
                }

                Comment


                • #9
                  The "above condition" is several conditions depending on which variable is being considered.

                  Reformatting your code (please do take the time to read the FAQ Advice and learn how to do this properly)

                  Code:
                  local a cat dog llama
                  local aa moose squirrel alpaca
                  local n : word count `a'
                  generate total_obs = 0
                  forvalues i = 1/`n' {
                      replace total_obs = total_obs + count `: word `i' of `a'' if `: word `i' of `aa''==1
                  }
                  your code won't be seen as an attempt to use count by Stata. It's just fantasy syntax!

                  This should work:

                  Code:
                  local a cat dog llama
                  local aa moose squirrel alpaca
                  local n : word count `a'
                  
                  forvalues i = 1/`n' {
                      gettoken AA aa : aa
                      di "`AA':"  
                      count if  `AA' ==1
                  }
                  }
                  and that yields a display of several counts.

                  Comment


                  • #10
                    Looking at the code in #8, I think the following is what was wanted. The key is realizing that for this situation "counting" is the same as "totaling" a constant value of 1.
                    Code:
                        replace total_obs = total_obs + 1 if `: word `i' of `aa''==1
                    You can of course use a single loop to calculate both total (from post #4 above) and total_obs (from this post).

                    Comment


                    • #11
                      William: Agreed that might be wanted. If so, then this also works:


                      Code:
                       
                       replace total_obs = total_obs + (`: word `i' of `aa''==1)

                      Comment

                      Working...
                      X