Announcement

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

  • local macro loop

    Hi,
    I'm trying to automate the following code
    gen ysr1 = . // Initialize with missing values
    replace ysr1 = ysr1_actedtooyoung_0 if time == 0
    replace ysr1 = ysr1_actedtooyoung_1 if time == 1
    replace ysr1 = ysr1_actedtooyoung_2 if time == 2

    I have 118 YSR variables and have set up a local macro but the looping isn't working and I'm not sure why. It does not return any errors.

    TIA,
    Kim


    // Create a local macro with all the base variable names
    local baseNames ysr1_actedtooyoung ysr2_alcnoparntapprvl ysr3_arguedalot ysr4_failtocomplete ysr5_enjoyedlittle ///
    ysr6_likedanimals ysr7_bragged ysr8_cantconcentrate ysr9_thoughttoomuch ysr10_cantsitstill ///
    ysr11_dependentonadults ysr12_feltlonely ysr13_feltconfused ysr14_criedalot ysr15_prettyhonest ///
    ysr16_meantoothers ysr17_daydreamedalot ysr18_attempthurtokillself ysr19_triedtogetattention ysr20_destroyedownthings ///
    ysr21_destrydothrsthngs ysr22_disobeyedparents ysr23_disobeyedatschool ysr24_noteatenwell ysr25_dntgetalongotkids ///
    ysr26_nogltaftrdoingsmthng ysr27_jeolousofothers ysr28_brokerules ysr29_afrdstionsnotsch ysr30_afraidofsch ///
    ysr31_afraiddosomethingbad ysr32_felthavetobeperfect ysr33_feltnoonelovesme ysr34_feltothersouttogetme ysr35_feltworthless ///
    ysr36_accidentgothurt ysr37_foughtotchildren ysr38_gotmadefunof ysr39_aroundtroublesomekids ysr40_heardsoundsorvoices ///
    ysr41_actedwithoutthinking ysr42_ratherbealone ysr43_liedorcheated ysr44_bitingfingernails ysr45_nervsoranxs ///
    ysr46_twtchdornrvsmvmnt ysr47_nightmares ysr48_notlkdbyothrkids ysr49_dothngsbtrthnotkids ysr50_toofrfuloranxs ///
    ysr51_dizzyorlightheaded ysr52_feltguilty ysr53_eatentoomuch ysr54_ovrtrdwthoutrsn ysr55_feltoverweight ///
    ysr56a_achesorpains ysr56b_headaches ysr56c_nausea ysr56d_eyeproblem ysr56e_rash ysr56f_stomachache ysr56g_vomiting ///
    ysr57_attackedpeople ysr58_pickdskinorothrprts ysr59_prettyfriendly ysr60_liketotrynewthings ///
    ysr61_poorschoolwork ysr62_prlycrdinatedorclumsy ysr63_ratherbewitholdrkids ysr64_ratherbewithyngerkids ysr65_refusedtotalk ///
    ysr66_repeatedcertainacts ysr67_runawayfromhome ysr68_screamedalot ysr69_secretive ysr70_seethngsothrscantsee ///
    ysr71_slfcncseslyembrsd ysr72_setfires ysr73_workedwellwithhands ysr74_showofforfoolaound ysr75_tooshyortimid ///
    ysr76_sleptlessthanmostkids ysr77_sleptmorethanmostkids ysr78_daydrmeslydstrctd ysr79_speechproblems ysr80_stoodupformyrights ///
    ysr81_stolenathome ysr82_stlnfrmplcnthme ysr83_storedthingsidontneed ysr84_donestrangethings ysr85_hadstrangethoughts ///
    ysr86_stubborn ysr87_suddenmoodchanges ysr88_enjydbeingwthppl ysr89_suspicious ysr90_swornordirtylanguage ///
    ysr91_thoughttokillself ysr92_likdmakngothrslaugh ysr93_talkedtoomuch ysr94_teasedothersalot ysr95_hottemper ///
    ysr96_thoughtofsextoomuch ysr97_threatentohurtpeople ysr98_likedhelpingothers ysr99_smokedtobacco ysr100_troublesleeping ///
    ysr101_skippedschool ysr102_lowenergy ysr103_feltunhappy ysr104_louderthanotherkids ysr105_drugsnonmedpurposes ///
    ysr106_fairtoothers ysr107_enjoyedgoodjoke ysr108_takelifeeasy ysr109_helpothers ysr110_wishwasoppositesex ///
    ysr111_avdnvlvmntwthothrs ysr112_worriedalot

    *local numVariables : word count `baseNames'

    /// Loop over the range from 1 to the number of variables
    forval i = 1/118 {
    // Create new variable ysr`i' with missing values initially
    gen ysr`i' = .

    // Loop over each base name
    foreach base in `baseNames' {
    // Extract the full base variable name (e.g., 'ysr10_cantsitstill') to match with 'ysr`i''
    local baseVarName "`base'"

    // Construct the complete base variable names for different time points
    local varname0 "`baseVarName'_0"
    local varname1 "`baseVarName'_1"
    local varname2 "`baseVarName'_2"

    // Replace the value in ysr`i' based on the value of time and the corresponding varname
    replace ysr`i' = `varname0' if time == 0
    replace ysr`i' = `varname1' if time == 1
    replace ysr`i' = `varname2' if time == 2
    }
    }

  • #2
    You don't seem to have 118 names there. Also, this problem is at most one with loops in parallel, not nested loops. See e.g. https://journals.sagepub.com/doi/pdf...6867X211063415

    Try this -- given your definition of basenames

    Code:
    foreach name of local basenames { 
    
    local new = substr("`name'", 1, strpos("`name'", "_") - 1)  
    
    gen `new' = `new'_0 if time == 0
    replace `new' = `new'_1 if time == 1
    replace `new' = `new'_2 if time == 2
    
    }

    Comment


    • #3
      I have a question for you Nick Cox on this. I have never managed to wrap my head around when and how Stata treats wildcards * or ~ or ?. Maybe you can help enlighten me.
      From post #1 my immediate thought was to clonevar:
      Code:
      forval num = 1/118 {
          clonevar ysr`num' = ysr`num'*_0 if time == 0
      }
      But then I know * would not work the same way with the replace command. How come?
      Code:
      replace  ysr`num' = ysr`num'*_1 if time == 1
      Thank you.

      Comment


      • #4
        clonevar is official but was first written by me. Your syntax is illegal as

        Code:
        ysr`num'*_0
        counts as an expression (but if and only if _0 is the name of a numeric scalar or variable) -- but an expression including an operator is illegal there as only a plain variable name is allowed.

        More generally. a tautological answer, but also I hope a logical answer, is that wildcards are allowed as part or all of a varlist if and only if a varlist is allowed at the place you're at. A varlist as you know is a list of variable names.

        The expression to the right of an equals sign can, I think, never be such a place, as two or more variables can often be mentioned but only with operators or functions too to spell out how they are to be combined.

        Comment


        • #5
          Thank you for the answer. That clarifies it massively for me.

          Also, for reply #2 I think you probably meant `name'_0:
          Code:
          foreach name of local basenames { 
          
          local new = substr("`name'", 1, strpos("`name'", "_") - 1)  
          
          gen `new' = `name'_0 if time == 0
          replace `new' = `name'_1 if time == 1
          replace `new' = `name'_2 if time == 2
          
          }

          Comment


          • #6
            Wei Hai Deng Indeed and thanks. Good catch!

            Comment


            • #7
              Nick Cox Thanks very much!

              Comment


              • #8
                Hi,

                I am learning how to use macro and loop over the past few months. I found that it is essential to any data management tasks.
                Right now, I am working on a data set that has variables named: q14a1 q14a2 q14a3 q14a4 q14a5 q14a6 q14b1 q14b2 q14b3 q14b4 q14b5 q14b6 q14c1 q14c2 q14c3 q14c4 q14c5 q14c6 ... q14x1 q14x2 q14x3 q14x4 q14x5 q14x6. I need to generate new variables using a1 and a2, a3 and a4, a5 and a6 respectively. Then moving on to the next sequence of variables, b1 and b2, b3 and b4, b5 and b6 respectively, so on and so forth. Basically, I need to repeat the following commands:

                g mechanical_k4 = 1 if q14a1==1 | q14a2 ==1
                replace mechanical_k4 = 0 if q14a1!=1 & q14a2 !=1

                g mechanical_58 = 1 if q14a3==1 | q14a4 ==1
                replace mechanical_58 = 0 if q14a3!=1 & q14a4 !=1

                g mechanical_9 = 1 if q14a5==1 | q14a6 ==1
                replace mechanical_9 = 0 if q14a5!=1 & q14a6 !=1


                g electrical_k4 = 1 if q14b1==1 | q14b2 ==1
                replace electrical_k4 = 0 if q14b1!=1 & q14b2 !=1

                g electrical_58 = 1 if q14b3==1 | q14b4 ==1
                replace electrical_58 = 0 if q14b3!=1 & q14b4 !=1

                g electrical_9 = 1 if q14b5==1 | q14b6 ==1
                replace electrical_9 = 0 if q14b5!=1 & q14b6 !=1

                I read the tutorial on "loops in parallel" and tried to come up with the code. I know this is not right but I am stuck, so I'd appreciate any insights.

                local name "q14a q14b q14c"
                local i = 1
                foreach var of local name {
                g `new' = 1 if `name'`i' ==1 |`name'`++i' ==1
                }

                Comment


                • #9
                  The first trick to learn is that two-steps such as

                  Code:
                  g mechanical_k4 = 1 if q14a1==1 | q14a2 ==1
                  replace mechanical_k4 = 0 if q14a1!=1 & q14a2 !=1
                  can be condensed into one such as

                  Code:
                  g mechanical_k4 = q14a1==1 | q14a2==1
                  and indeed if (and only if) 1 is the only non-zero value present then

                  Code:
                  g mechanical_k4 =  q14a1 | q14a2
                  would work too. Note: missing values would break that code.

                  See e.g. https://www.stata.com/support/faqs/d...rue-and-false/ or https://journals.sagepub.com/doi/pdf...36867X19830921

                  There isn't a way that is obvious to me to write code for what you want that is simpler than

                  Code:
                  g electrical_k4 = q14b1==1 | q14b2==1
                  g electrical_58 = q14b3==1 | q14b4==1
                  g electrical_9 =  q14b5==1 | q14b6==1
                  Think of it this way. You have to loop over the old names and the new names. If anyone can think of a loop that takes three lines, that would be clever, but is it clearer than the above? Your code must be clear to you when you write and clear to anyone who needs to read it to understand, modify or even debug it. And "anyone" could be you in 1 day, 1 week, 1 month, 1 year, ....
                  Last edited by Nick Cox; 15 Nov 2023, 09:19.

                  Comment


                  • #10
                    Note that

                    Code:
                    inlist(1, q14b1,  q14b2)
                    is an alternative to
                    Code:
                     
                     q14b1==1 | q14b2==1

                    Comment


                    • #11
                      Thanks, Nick, these tricks save me lots of keystrokes.
                      Last edited by Tingting Tan; 17 Nov 2023, 18:06.

                      Comment

                      Working...
                      X