Announcement

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

  • Setting loop # equal to the specific value of a variable

    Hi all,

    I am trying to automate a process using a loop to run X number of times, where X is equal to the value of a specific variable that has been created. This number needs to vary based on the value of the variable in each dataset that gets created in different sections of my .do file. I've tried the following code, but Stata does not recognize the value of `n' below, even though it is stored in the local macro. Note that 'var1' is a variable I generated that only has the same value in all rows.

    Code:
     local n (var1 - 1)
      forvalues i = 1/`n' {
      bysort var1: replace var2 = 1 if _n == 1 & var3 == 1 
      egen var5 = total(var4), by(id)
      replace var4 = var5 if var5 == 1
      drop var5
    }
    The content of the loop is somewhat irrelevant here--basically it's a process that creates different variables based on row numbers etc. -- but what I'm interested in is, how can you program a loop to run a set number of times, equal to the value of a specific variable (and/or cell).

    Thanks in advance!

    Cheers,
    John

  • #2
    If you look at the local macro you created

    Code:
    display "`n'"
    you will see that it does not contain the value you want. It contains the expression used to define it, which is copied literally as a string.

    You would need to evaluate that expression when defining the local macro for the result to be useable in a forvalues loop.

    Code:
      
    local n = var1 - 1
    However, that is only one problem solved. Your statement that the contents of the loop are "somewhat irrelevant" implies that the rest of the code is fine. But each time you go round the loop you carry out exactly the same operations, as your code makes precisely no reference to the local macro. So, either no loop is needed at all, or you need to reconsider your code.

    Comment


    • #3
      Thank you for that explanation Nick. When I try local n = var - 1 , and then display "`n'", it shows the correct value for the number of times I want the loop to run, but then when I run the loop with "set trace on", I get the following result:

      Code:
      - forvalues i = 1/`n' {
      = forvalues i = 1/ {
      invalid syntax
      So I see what you mean, `n' is showing up as blank there because it doesn't read a number but rather a string.

      You're right, the contents are not irrelevant--let me try to be more clear. As you point out, I do not actually want to make any reference to the contents of `n' within the loop itself, which I understand is an unconventional (and apparently unsuccessful) way of using that local. What I am trying to do is to set the # of times the loop repeats to be dependent on the value of a specific variable. The value of that variable is going to vary in different parts of the .do file, but in order to automate the process, it is crucial that the loop be able to be correlated to the value of this specific variable. Is there any way to do this? I understand that it's not possible to set: forvalues i = 1 / var1 , for example. Here is the full code which I would like to have repeat, varying on the value of var1.

      Code:
        forvalues i = 1/`n' {
        sort id bestcontrol
        bysort id: replace idtaken = 1 if _n == 1 & bestcontrol == 1 
        egen totalidtaken = total(idtaken), by(id)
        replace idtaken = totalidtaken if totalidtaken == 1
        drop totalidtaken
         
        *Update idindexfree var to incorporate new pairs that have been taken and are no longer available*
        sort index bestcontrol
        bysort index: replace indextaken = 1 if _n == 1 & bestcontrol == 1
        egen totalindextaken = total(indextaken), by(index)
        replace indextaken = totalindextaken if totalindextaken == 1
        drop totalindextaken
         
        *If a treatment area is still left without a control area pair, give it the best possible available control area*
        replace idindexfree = . if idtaken == 1 | indextaken == 1
         
        *Keep only unique Treatment - Control pairings for this department*
        sort idindexfree dist id
        replace bestcontrol = 1 if _n == 1
        }

      Comment


      • #4
        On the first part, the error you get should not be that there's an empty macro, nor did I predict that. The error you should get is that forvalues can't make sense of the argument supplied. So, I surmise that you are doing something else, specifically defining the local macro in one place and then trying to use it in another. That's what local means.

        It's not out of order to give examples that are not your real code, but I find that I spent my time trying to understand some code that wasn't your real example.

        OK, because the real code is much more complicated, and you judged it irrelevant, but the major point remains: if the same code does something differently each time round the loop, then it's certainly legal and possibly useful to have a loop that doesn't refer to the macro inside the loop. Whether your code qualifies I can't say, but there is no barrier to doing what you want, namely calculate the number of iterations in advance. My comment before was that example code doesn't do anything different, so the loop is pointless.

        Comment


        • #5
          Great, thank you for that information Nick, that cleared things up. I tried using a global instead, and was able to run exactly what I needed. Thanks again!

          Comment


          • #6
            I have a clarifying question about what you're trying to do. Is the variable that you are using to determine how many times you loop a constant? You haven't given the exact code you use to set up your n now that you decided to make it global but I'm assuming it's something like
            Code:
            global n=var1-1
            In that case your n value will be the value of var1 from the first observation minus 1. If var1 is constant across all observations, this is fine. If your intent is to run the loop a different number of times for different observations, however, this won't work. It's unclear from your comment above about wanting to do this for varying values of var1 whether var1 varies across observations in a single dataset (in which case this strategy will not work) or whether it is constant within a dataset but varies across multiple datasets (in which case this strategy could work).

            Comment


            • #7
              Sarah, thank you so much for catching this. The variable being used is not a constant. Basically there are four different datasets that will contain that same variable, but in each dataset, the value of this variable will be different.

              The code I was using was indeed:

              Code:
               global n = var1 - 1
              Based on your comments, I've decided that the safest strategy is to re-define the global in each section (i.e. after each dataset is opened), so that right before each loop, I use that same code (global n = var1 - 1) after each new dataset gets opened in the .do file. This then takes care of the issue. I imagine there may be some short cut way of doing this, but for my purposes, this way seems to be taking care of what is needed.

              I really appreciate that you caught this, Sarah!

              Comment

              Working...
              X