Announcement

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

  • Using a loop with local and extended macros to generate new recoded variables, variable labels, and value labels

    I am generating a series of new variables that represent recoded versions of existing variables. At the same time, I am labeling the new variable and labeling the values of the new variables. To make my code more succinct, I am using macros to hold a list of old and new variable names and extended macros to call each name in the list.

    When I run the following code, I get the error message "invalid syntax" after the last line of the loop below ("label `var2' ...). Note the name I intended to give the variable displayed in the trace is correct.

    Sample code with three variables:

    local oldvar food diet meals
    local newvar F1 F2 F3
    label define F3way 0 "Never true" 1 "Sometimes true" 2 "Often true"
    forval i = 1/3 {
    local var1 `: word `i' of `oldvar''
    local var2 `: word `i' of `newvar''
    gen `var2' =0 if `var1' ==3
    replace `var2' =1 if `var1' ==2
    replace `var2' =2 if `var1' ==1
    label values `var2' F3way
    label `var2' "Recode `var1'"
    }

    Could you please help me understand where I've gone wrong? Thank you
    in advance for your assistance!

    Lois Fisher

  • #2
    Hi Lois. I cannot get your question very clearly. So this is only a guess from your posted code. Your purpose could be clarified into two parts:
    (1) Generate a series of new variables from current old variables.Exchange the values with the rule: 3-->0, 2-->1 and 1-->2.
    (2) Label the new variables with the defined labels F3way.
    If this is correct, you may take the code as a reference:
    Code:
    * Example generated by -dataex-. To install: ssc install dataex
    clear
    input double(food diet meals)
    1 2 3
    2 3 1
    3 1 2
    end
    label define F3way 0 "Never true" 1 "Sometimes true" 2 "Often true"
    foreach var of varlist _all{
      gen F_`var'=0 if `var'==3
      replace F_`var'=1 if `var'==2
      replace F_`var'=2 if `var'==1
      label value F_`var' F3way
    }
    2B or not 2B, that's a question!

    Comment


    • #3
      No loops needed. If you want to recode variables, use the recode command.

      The basic setup is this

      Code:
      recode food diet meals     ///
          (3=0 "Never true")     ///
          (2=1 "Sometimes true") ///
          (1=2 "Often true")     ///
          , generate(F1 F2 F3) label(F3way)
      where recode automatically creates variable labels similar to the ones you have in mind.

      Best
      Daniel

      Comment


      • #4
        Thank you both! Lessons learned from both posts. I have a few remaining questions, if you would be so kind.

        First, some additional context:

        a) I am looking for a precise renaming for the new variable because I am working on the latest update to panel data. To maintain consistency across published data, I need to merge the latest update with the last analyst's final data associated with the previous update, including that analyst's particular variable names and recoding schemes.

        b) I am working on sets of variables that are >3 in length. The sets are coming from sections of survey questions with similar content. As I work through the variable preparations in different sections, I will be doing operations that focus on subsets or the entire list of variables from that section of the survey. For example, I may want one loop to change variables 1-10 of the total 20 variables in one section and perhaps in another loop I'm targeting only the 15th and 18th variables in that same section.

        Additional questions (if you would be so kind):

        1) .Sequencing through longer variable lists or choosing selected members of a long list.

        There are four goals I'm trying to meet. The first three goals are done in one loop: a) generating a new variable; b) recoding the values of the new variable; c) labeling the recoded values in the new variable. I think Daniel Klein's reminder about recode efficiently addressed all three of these goals. A fourth goal is the ability to write loops that apply to subsets of longer variable lists or even just a few members of that list. Could your suggested code by modified to meet all four goals?

        2) I did try employing recode following Daniel Klein's reminder to use this terrific function. I'm still getting an error(r198 at the end of the trace, no other information). My adapted code below.

        Code:
        clear
        input double(doe rei mi fah sol la ti do)
        12352852
        23128582
        31282528
        end
        local oldvar do rei mi fah sol la ti do
        local newvar note1 note2 note3 note4 note5 note6 note7 note8
        set trace on
        forval `i' = 1/3 {
            local var1 `: word `i' of `oldvar'
            local var2 `: word `i' of `newvar'
            recode `var1' ///
                (3=0 "Never true") ///
                (2=1 "Sometimes true") ///
                (1=3 "Often true"), ///
                gen(`var2') label("Recode `var1'")
            }
        2-note) I think the labeling of the new variable (variable name) is the sticking point in my program. Perhaps I have a problem of how I'm using the double quotes?

        Finally, my apologies for not posting the input code for a set of sample data. I had written it but decided not to include it, judging that my question was fairly basic. Next time I'll post an input sample to ease the work on your side regardless of my judgement about the difficulty of the question!

        Thanks again!
        Lois Fisher
        Last edited by Lois Fisher; 23 May 2019, 12:03.

        Comment


        • #5
          Code modified to address problem of double quotes + syntax in "forvalues". This works!

          Any suggestions on a more efficient approach very welcome! I do have working code now, so no reply absolutely necessary.
          Sorry for the two posts one after the other! Thank you again!

          Lois Fisher

          Code:
          clear
          input double(do rei mi fah sol la ti do)
          12352852
          23128582
          31282528
          end
          local oldvar do rei mi fah sol la ti do
          local newvar note1 note2 note3 note4 note4a note5 note6 note7
          set trace on
          forval i = 1/3 {
          local var1 `: word `i' of `oldvar''
          local var2 `: word `i' of `newvar''
          recode `var1' ///
          (3=0 "Never true") ///
          (2=1 "Sometimes true") ///
          (1=3 "Often true"), ///
          gen(`var2') label("Recode ``var1''")
          }
          Last edited by Lois Fisher; 23 May 2019, 12:33.

          Comment


          • #6
            Some short comments. The example you provide does not work for various reasons. You want

            Code:
            clear
            input double(doe rei mi fah sol la ti do)
            1 2 3 5 2 8 5 2
            2 3 1 2 8 5 8 2
            3 1 2 8 2 5 2 8
            end
            note the spacing. Also, note that you have misspelled the first variable name, leading to an error because variable do can only be defined once. By the way, those variables do not require storage type double; byte would suffice, but that is not important.

            Although the code seems to work for you, I do not believe that it does exactly what you want.

            Code:
            recode [...]
            gen(`var2') label("Recode ``var1''")
            does not define a variable label, as you might think (but perhaps you are aware of that). Type

            Code:
            describe
            to see that all variable labels are of the form "RECODE of ..." (note all caps and the word "of" which does not appear in the label() option.

            Option label() expects a name for a value label. Names cannot contain spaces in Stata. In my opinion, the label()option should not even allow double quotes. Anyway, you got away by using nested single quotes; ``var1'' evaluates to `' in the first step, then to "", i.e., missing string. As a result, recode (re-)creates one value label with the name Recode. Type

            Code:
            describe
            to see what the labels actually look like. If you want one value label per variable (not recommended if the integer-to-text mappings are all identical), you want something like

            [code]
            Code:
            recode [...]
            gen(`var2') label(Recode_`var1')
            Perhaps, you want to add a line for the variable label if it is important to you.

            Best
            Daniel

            Comment


            • #7
              Daniel,

              Yes, I see now what you're saying. I was confusing the variable label (name the variable) with the value label in the context of the recode syntax. I fixed that in my code and added the variable label (name) as a separate line. The spacing error at the data input step was a copy and paste mistake.

              I'm not sure why I haven't been making better use of the recode function but I certainly will now.

              Thank you very much for your attention to this fairly basic question. I often work on my own without much coaching, which means I can continue with inefficient approaches too long, whether on more complex questions or fairly basic tasks taken on during variable preparation. This is true even though I regularly consult Stata manuals, Stata forum posts and other help pages. I think I will be posting to the Stata Forum more often to leverage the brain trust here. You are all so kind to stop and help the struggling lot of us.

              Lois

              Comment

              Working...
              X