Announcement

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

  • If macro equals multiple values or range

    I need that Stata will do something if a global is equal to the value 7 or 8 (or in a range). I have stumbled upon Nick's answer (https://www.stata.com/statalist/arch.../msg00810.html) which is in the direction of what I am looking for -
    Code:
    if strpos("$global", "7") {
     ...
     }
    But I do not know how to make this argument a range or more than one number.
    Stata/MP 15.1

  • #2
    Code:
    if inlist("$global", "7", "8")
    or

    Code:
    if inlist( $global, 7, 8)
    may be a way forward, depending on whatever else is going on. We should add, before Clyde Schechter points it out, that use of globals is generally poor programming style. Much better ways to exist to pass information around.

    Comment


    • #3
      What would you do instead of global and why is it better?
      Stata/MP 15.1

      Comment


      • #4
        Use a local macro. It is better because it is safer. A global macro is accessible all up and down the "chain of command" of programs. You can define it in one place and modify it in another. This may sound like wonderful freedom and flexibility, but the price is that when you use a global macro you can never really be sure what is in it. If you put some information in a global macro, and then between that point and when you want to use it you call some program, maybe a part of official Stata, or maybe something a user wrote (or maybe something you wrote a long time ago and haven't thought about since), it might be that that program also uses a global macro with that name and makes changes to it. If that happens, when control returns to the place where you initialized the macro, it now has something different in it. And you have no warning of this. Also, you generally don't know what programs are going to be active during your run--because the program you call directly may have a whole tower of programs called by it. And any one of them can mess with your global macro. When this kind of thing happens, the bugs it produces appear bizarre and are extremely difficult to track down and fix. In the circumstances where a global macro is truly the only available approach, you should pick an exotic name, like a hard password, to minimize the likelihood that some other program will also have a global macro of that name.

        A local macro never has this problem because its scope is restricted to the program (or highlighted block of code in a do-file editor) in which it is created. If another program called, directly or indirectly by yours, has a local macro of the same name, they are different macros and changes to one do not affect the other. They are completely safe.

        So you should only use a global macro when it is essential to transmit information up and down between a sequence of programs that call each other and when there is no other reasonable way to do it. (Usually this can be done by including options in the syntax of the program call.) I have been using Stata for a little over 25 years now and in all that time I have found exactly one situation where I actually had to use a global macro.

        Comment


        • #5
          See also -inrange-

          Comment


          • #6
            Dear Clyde, I fully understand and agree with this. However, I have began using globals when locals could not be recalled by Stata when I ran 2 sets of command lines. So, for example I initially define the mechanism by which the regressions will run (where the dataset is located, the sets of regressors to be used in each set of regressions [I run 3 sets each time], I set the timer on and off before each estimation to get an idea of which specifications delay the process, where to save and how to produce the LaTeX table of each estimation and how to name it .... etc.). After this, it is much simpler to define the name of each set of regressions and change the specification accordingly. This cannot be done with locals as far as I understand. Here is my do file - do you think I can use locals? If so I will be happy to work safer and I understand the risk of using globals.

            Code:
            ***********************************************************************
            * Regressions
            ***********************************************************************
            
            ***********************************************************************
            * Globals
            ***********************************************************************
            * Use merged clean
            clear
            global patha "/Users/morzahavi/Library/Mobile Documents/com~apple~CloudDocs/Dissertation/"
            global pathb "Chapter 2/Data/Stata Data Files/PISA_School_Student_Merged_Clean/"
            * Output
            global pathc "/Users/morzahavi/Library/Mobile Documents/com~apple~CloudDocs/Dissertation/"
            global pathd "Chapter 3/"
            * Charecteristics
            * File version
            global ver 201911281007
            global chap 3
            global font CMUSerif-Roman
            * Regression program 
            * Regrssions
            global refcat1 immig1
            global refcat1label "Immigration status"
            global refcat2 ed_mo_1
            global refcat2label "Education"
            * Regular regressions
            capture program drop myestroutine
            program myestroutine
            * Use merged clean
            clear
            use "${patha}${pathb}Merged_clean.dta"
            * Start routine
            *eststo clear
            timer clear
            forvalues i=1(1)3{
            * Variables
            global reg1 "female books* immig*"
            global reg2 "female books* immig*"
            global reg3 "female books* immig* ed*"
            global dropvars "books*"
            timer on `i'
            if inlist("$number", "7", "8"){
            $surveyset
             }
            $myreg ${reg`i'}, $options1
            timer off `i'
            timer list
            estadd scalar R = r(t`i')
            eststo Model_`letter'_`i'
            }
            end
            * REPEST regressions
            capture program drop myrepestroutine
            program myrepestroutine
            * Use merged clean
            clear
            use "${patha}${pathb}Merged_clean.dta"
            * Start routine
            *eststo clear
            timer clear
            forvalues i=1(1)3{
            * Variables
            global reg1 "female books* immig*"
            global reg2 "female books* immig*"
            global reg3 "female books* immig* ed*"
            global dropvars "books*"
            global dropint "*cntry"
            timer on `i'
            $myrep ${reg`i'}, $repoptions1
                matrix list e(b)
                matrix coeff = e(b)
                scalar b_n = coeff[rownumb(coeff,"y1"),colnumb(coeff,"e_N")]
                scalar b_r = coeff[rownumb(coeff,"y1"),colnumb(coeff,"e_r2")]
            timer off `i'
            timer list
            estadd scalar N = b_n
            estadd scalar r2 = b_r
            estadd scalar R = r(t`i')
            eststo Model_${letter}_`i'
            }
            end
            * Export to LaTeX
            capture program drop mylatexroutine
            program mylatexroutine
            * Write output to 
            cd  "$pathc$pathd$ver/Tables"
            cap mkdir "$tab"
            cd "$tab"
            * Export
            esttab Model_${letter}_1 Model_${letter}_2 Model_${letter}_3 using $tab.tex, /// 
            label replace booktabs  ///
            alignment(D{.}{.}{-1}) width(\hsize) ///
            nonumbers mtitles ///
            nodepvar nonotes ///
            title(${table}\label{tab$number}) ///
            drop( _cons $dropvars e_N e_r2) ///
            star(* 0.10 ** 0.05 *** 0.01) ///
            stats(N r2 R, fmt(%12.0fc 2 2) /// 
            labels("N" "R-squared" "Time")) ///
            refcat($refcat1 "\emph{$refcat1label}" $refcat2 "\emph{$refcat2label}" , nolabel)
            end
            ***********************************************************************
            * Table 1: Simple regression
            ***********************************************************************
            * Table Name
            global tab mz3_regtab_sr
            global letter a
            global number 1
            global myreg quietly reg pv1math lbe 
            global options1
            myestroutine 
            mylatexroutine
            ***********************************************************************
            * Table 2: Simple regression with standardised scores
            ***********************************************************************
            * Table Name
            global table Simple regression with standardised scores
            global tab mz3_regtab_sr_ss
            global letter b
            global number 2
            global myreg quietly reg numscore1 lbe  
            local options1
            myestroutine 
            mylatexroutine
            ***********************************************************************
            * Table 3: Multi level (country) regression with standardised scores
            ***********************************************************************
            * Table Name
            global table Multi level (country) regression with standardised scores
            global tab mz3_regtab_mlc_ss
            global letter c
            global number 3
            global myreg quietly mixed numscore1 lbe  
            global options1  || country: 
            myestroutine 
            mylatexroutine
            ***********************************************************************
            * Table 4: Multi level (schoolid) regression with standardised scores
            ***********************************************************************
            * Table Name
            global table Multi level (schoolid) regression with (ss)
            global tab mz3_regtab_mlsid_ss
            global letter d
            global number 4
            global myreg quietly mixed numscore1 lbe  
            global options1  || schoolid:
            myestroutine 
            mylatexroutine
            Last edited by Mor Zahavi; 22 Dec 2019, 05:47.
            Stata/MP 15.1

            Comment


            • #7
              Every one of those globals could be a local instead. The only complication would be the need to change the syntax of the programs you defined so that the information that you pass in globals is instead passed as an option to the program. The general scheme is simple:

              Code:
              local path C:/my_working_directory/my_subdirectory
              local filename myfile
              
              …
              ...
              
              capture program drop my_program
              program define my_program
                  syntax, path(string) file(string)
                 ….
                 use `path'/`file', clear
                 …
              end
              
              …
              …
              
              my_program, path(`"`path'"') file(`"`filename'"')
              …
              ...
              Note one additional precaution when dealing with paths and filenames: because the sequence \` would be interpreted by Stata as a literal ` character rather than a path separator followed by the start of a local macro reference, it is better to use / as a path separator, even if you are running Windows. All Stata's file handling commands will automatically pass \ instead of / to Windows, but they will do it after they have properly handled all macros.
              Last edited by Clyde Schechter; 22 Dec 2019, 10:21.

              Comment


              • #8
                See also :

                https://www.stata-journal.com/sjpdf....iclenum=pr0047


                If you define your locals in a separate file you can 'include' them in different -do- files or at different places in the same -do- file.

                Jeph

                Comment


                • #9
                  Originally posted by Clyde Schechter View Post
                  Every one of those globals could be a local instead. The only complication would be the need to change the syntax of the programs you defined so that the information that you pass in globals is instead passed as an option to the program. The general scheme is simple:

                  Code:
                  local path C:/my_working_directory/my_subdirectory
                  local filename myfile
                  
                  …
                  ...
                  
                  capture program drop my_program
                  program define my_program
                  syntax, path(string) file(string)
                  ….
                  use `path'/`file', clear
                  …
                  end
                  
                  …
                  …
                  
                  my_program, path(`"`path'"') file(`"`filename'"')
                  …
                  ...
                  Note one additional precaution when dealing with paths and filenames: because the sequence \` would be interpreted by Stata as a literal ` character rather than a path separator followed by the start of a local macro reference, it is better to use / as a path separator, even if you are running Windows. All Stata's file handling commands will automatically pass \ instead of / to Windows, but they will do it after they have properly handled all macros.
                  It took me 5 months to understand what you meant here Clyde. I new it was important but it took a while before I had time to fiddle with it in my free time. You are absolutely right and thank you for pointing this out. I have invested some time in it but it was worth it.
                  Stata/MP 15.1

                  Comment

                  Working...
                  X