Announcement

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

  • Very basic : Defining programs in stata + Returning and storing of values

    Hello statalisters,

    I've been struggling with this for a while so I had to ask this on statalist.

    I'm currently getting familiar with the program concept and I've done one myself. The purpose is to return the mean of a variable passed as an argument

    Code:
    sysuse auto, clear
    program drop _all
    
    capture drop program prog1
    program define prog1
        version 13.0
        syntax varname
        qui sum `varname'
        local moy=r(mean)
        dis `moy'    
    end
    
    
    sum weight
    dis r(mean)
    
    prog1 weight
    The problem is that this program displays a value that is different from the mean of weight of the auto.dta.
    How can I correct this?

    ===
    My second problem is : I would like to design a program that returns to me a local (macro) that I can then store and use. I know that there is this s() command, but I don't how to use it.

    Code:
    sysuse auto, clear
    program drop _all
    
    capture drop program prog1
    program define prog1
        version 13.0
        syntax varname
        qui sum `varname'
        local moy=r(mean)
        *dis `moy'    
        return local `moy'
    end
    
    
    prog1 weight
    local mu=s(local) // r(151) error
    Thank you for your kind help

    Dusan

  • #2
    So, there are a couple of problems with your code. Although the -syntax- statement allows you to specify varname, a peculiarity is that the resulting variable name is not stored in `varname', it is stored in `varlist'. So when you get to -qui sum `varname'-, varname is, in fact, an undefined macro, which is interpreted as an empty string. Stata thus sees the command as -qui sum-, and, as -summarize- does when called with no varlist, it summarizes every variable in the data set. (If you hadn't put the -qui- prefix on you would have seen that.) The `r(mean)' is then the mean of the last variable, rather than the one you were hoping for.

    The second problem is that in order to have a program return a value, you have to specify that it is an -rclass- program when you define it. And the -return- command has to specify a name for the local you want it to return, as well as its values. In the code below I called it r(moy).

    So the following works:

    Code:
    sysuse auto, clear
    program drop _all capture drop program prog1
    program define prog1, rclass
        version 13.0
        syntax varname
        qui sum `varlist'
        local moy=r(mean)
        dis `moy'
        return local moy `moy'
    end
      
    sum weight
    dis r(mean)
    prog1 weight
    return list
    exit

    Comment


    • #3
      You need to study program, syntax and return. This does what you were looking for:
      Code:
      capture program drop prog1
      program define prog1, rclass
          version 13.0
          syntax varlist(min=1 max=1 numeric)
          qui sum `varlist'
          return local moy = r(mean)
      end

      Comment


      • #4
        THank you Clyde and Svend for your kind help.

        Comment


        • #5
          This is a related point to Dusan Petrovic's. I have the following program, which I call repeatedly. I want to be able to keep the `r(whatever)' output across executions, but it seems that any subsequent call to the program clears out all preceding r-class output. Below is an illustrative example:

          Code:
          sysuse auto, clear
          
          capture program drop first_coef
          program first_coef, rclass
              syntax, in1(string) in2(string) out1(name) out2(name) out3(name) out4(name)
              local firstname : word 3 of `in1'
              return local `out4' = `in2'
              return local `out1' = _b[`firstname']
              return local `out2' = _se[`firstname']
              
                   if inrange(2 * ttail(e(df_r), abs(_b[`firstname']/_se[`firstname'])),0.000000000,0.01) return local `out3' = "***"
              else if inrange(2 * ttail(e(df_r), abs(_b[`firstname']/_se[`firstname'])),0.010000001,0.05) return local `out3' = "**"
              else if inrange(2 * ttail(e(df_r), abs(_b[`firstname']/_se[`firstname'])),0.050000001,0.10) return local `out3' = "*"
              else return local `out3' = " "
          end
          
          qui reg price mpg headroom i.foreign 
          first_coef, in1(`e(cmdline)') in2(`e(N)') out1(b1A) out2(se1A) out3(star1A) out4(N1A)
          
          di `r(b1A)'
          di `r(se1A)'
          di "`r(star1A)'"
          
          qui reg price mpg headroom i.foreign i.rep78
          first_coef, in1(`e(cmdline)') in2(`e(N)') out1(b1B) out2(se1B) out3(star1B) out4(N1B)
          
          di `r(b1A)'
          di `r(se1A)'
          di "`r(star1A)'"
          
          di `r(b1B)'
          di `r(se1B)'
          di "`r(star1B)'"

          If you run the code, you'll see that the first set of -di `r(b1A)'- etc. display correctly, but once the program is called the second time, the only output available is `r(b1B)' etc.

          Is there a way to specify the program such that the macros stay in memory across multiple calls?

          All I really want is the number in `b1A', but as I understand it, writing the program as an r-class is the only way to extract this information.

          Any suggestions would be appreciated!

          Comment


          • #6
            inrange() here appears to be given four arguments. What am I missing?



            Comment


            • #7
              No, it only has three arguments. What looks like the second argument is actually nested within ttail().

              Comment


              • #8
                Update: I was able to get what I wanted by specifying globals instead of locals. It's not ideal, but it works.

                Code:
                sysuse auto, clear
                capture program drop first_coef
                program first_coef
                    syntax, in1(string) in2(string) out1(name) out2(name) out3(name) out4(name)
                    local firstname : word 3 of `in1'
                    global `out4' = `in2'
                    global `out1' = _b[`firstname']
                    global `out2' = _se[`firstname']
                    
                         if inrange(2 * ttail(e(df_r), abs(_b[`firstname']/_se[`firstname'])),0.000000000,0.01) global `out3' = "***"
                    else if inrange(2 * ttail(e(df_r), abs(_b[`firstname']/_se[`firstname'])),0.010000001,0.05) global `out3' = "**"
                    else if inrange(2 * ttail(e(df_r), abs(_b[`firstname']/_se[`firstname'])),0.050000001,0.10) global `out3' = "*"
                    else global `out3' = " "
                end
                
                qui reg price mpg headroom i.foreign 
                first_coef, in1(`e(cmdline)') in2(`e(N)') out1(b1A) out2(se1A) out3(star1A) out4(N1A)
                
                di ${b1A}
                di ${se1A}
                di "${star1A}"
                
                qui reg price mpg headroom i.foreign i.rep78
                first_coef, in1(`e(cmdline)') in2(`e(N)') out1(b1B) out2(se1B) out3(star1B) out4(N1B)
                
                di ${b1A}
                di ${se1A}
                di "${star1A}"
                
                di ${b1B}
                di ${se1B}
                di "${star1B}"

                Comment


                • #9
                  You're right. Sorry about that. Here's something more constructive.


                  Code:
                  capture program drop first_coef_2
                  program first_coef_2
                      syntax, in1(string) in2(string) OUTnames(string)
                      local firstname : word 3 of `in1'
                  
                      forval j = 1/4 {
                      local out`j' : word `j' of `outnames'
                      if "`out`j''" == "" {
                          local J = `j' - 1
                          di "only `J' names in out(): 4 names expected"
                          exit 498
                      }
                      }
                  
                      local garbage : word 5 of `outnames'
                      if "`garbage'" != "" {
                      di "trailing `garbage' in out(): 4 names expected"
                      exit 498
                      }            
                  
                      c_local `out4' = `in2'
                      c_local `out1' = _b[`firstname']
                      c_local `out2' = _se[`firstname']
                   
                      local Pvalue = 2 * ttail(e(df_r), abs(_b[`firstname']/_se[`firstname']))
                      if `Pvalue' <= 0.01         c_local `out3' "***"  
                      else if `Pvalue' <= 0.05     c_local `out3' "**"
                      else if `Pvalue' <= 0.1     c_local `out3' "*"
                      else                        c_local `out3' " "        
                  
                  end
                  
                  sysuse auto, clear
                  
                  
                  qui reg price mpg headroom i.foreign
                  first_coef_2, in1(`e(cmdline)') in2(`e(N)') out(b1A se1A star1A N1A)
                  
                  
                  qui reg price mpg headroom i.foreign i.rep78
                  first_coef_2, in1(`e(cmdline)') in2(`e(N)') out(b1B se1B  star1B N1B)
                  
                  mac li
                  
                  
                  . mac li
                  S_E_depv:       price
                  S_E_cmd:        regress
                  _star1B:        ***
                  _se1B:          66.38061998074737
                  _b1B:           -309.8902664464392
                  _N1B:           69
                  _star1A:        ***
                  _se1A:          59.5295636515793
                  _b1A:           -303.8203450613488
                  _N1A:           74
                  The output above excludes stuff not of interest here. The point is that local macros in the caller program's space won't be overwritten by running this program repeatedly in the same session, so long as you use different names.


                  This crossed with your use of globals, which in my view is not so good a solution.

                  Comment


                  • #10
                    Thanks, Nick! I did not know about the c_local command, and I also like passing all four outputs in one option. I appreciate you taking the time to clean up what I had written!

                    Comment

                    Working...
                    X