Search code examples
if-statementstatastata-macros

Use of local macro


I want to write six temp data files from my original data keeping the following variables:

  • temp1: v1-v18
  • temp2: v1-v5 v19-v31
  • temp3: v1-v5 v32-v44
  • temp4: v1-v5 v45-v57
  • temp5: v1-v5 v58-v70
  • temp6: v1-v5 v71-v84

I have tried the following:

forvalues i =1(1)6 { 
    preserve
    local j = 6 + (`i'-1)*13
    local k = `j'+12
    keep v1-v18 if `j'==6
    keep v1-v5 v`i'-v`k' if `i'>6 & `j'<71
    keep v1-v5 v71-v84 if `j'==71
    export delimited using temp`i'.csv, delimiter(";") novarnames replace
    restore 
}

I get an invalid syntax error. The problem lies with the keep statements. Specifically the if condition with a local macro seems to be against syntax rules.


Solution

  • I think part of your confusion is due to misunderstanding the if qualifier vs the if command.

    The if command evaluates an expression: if that expression is true, it executes what follows. The if command should be used to evaluate a single expression, in this case, the value of a macro.

    You might use an if qualifier, for example, when you want to regress y x if x > 2 or replace x = . if x <= 2 etc. See here for a short description.

    Your syntax has other issues too. You cannot have code following on the same line as the open brace in your forvalues loop, or again on the same line as your closing brace. You also use the local i to condition your keep. I think you mean to use j here, as i simply serves to iterate the loop, not identify a variable suffix.

    Further, the logic here seems to work, but doesn't seem very general or efficient. I imagine there is a better way to do this but I don't have time to play around with it at the moment - perhaps an update later.

    In any case, I think the correct syntax most analogous to what you have tried is something like the following.

    clear *
    
    set more off
    set obs 5
    forvalues i = 1/84 {
        gen v`i' = runiform()
    }
    
    
    forvalues i =1/6 { 
        preserve
        local j = 6 + (`i'-1)*13
        local k = `j'+12
        if `j' == 6 {
            keep v1-v18
        }
        else if `j' > 6 & `j' < 71 {
            keep v1-v5 v`j'-v`k'
        }
        else keep v1-v5 v71-v84
        ds
        di
        restore 
    }
    

    I use ds here to simply list the variables in the data followed by di do display a blank line as a separator, but you could simply plug back in your export and it should work just fine.

    Another thing to consider if you truly want temp data files is to consider using tempfile so that you aren't writing anything to disk. You might use

    forvalues i = 1/6 {
        tempfile temp`i'
        // other commands
        save `temp`i''
    }
    

    This will create six Stata data files temp1 - temp6 that are held in memory until the program terminates.