Following a beginning programming course is easier than following an advanced programming course. Why? Beginning programming involves writing simple programs, which can be shown in their entirety.
Advanced programming courses, on the other hand, quickly become a survey of advanced programming tools without context: here are all the tools you have for parsing, for manipulation, and so on, but it is difficult to show these advanced tools in use because they tend to be used in advanced programs, which are usually long. One solution is that advanced courses do not show the tools being used but just catalog them.
To avoid that, I have introduced the tools in the context of the mytt
program, but I do not want you to think this is a
course about how to program the t test. Moreover, you also need to understand
that we have taken a small problem and pounded it with sledgehammers, mainly
because I wanted to demonstrate the use of the heavy hammers.
Let's back up a minute and catalog what we have covered.
`1'
, `2'
, ... are the positional
parameters, and `0'
is what the user typed.syntax
can be used to parse `0'
.`0'
—or `1'
, `2'
, ...
—however we wish.`0'
—or `1'
, `2'
, ...
—over and over using different techniques.mark
and marksample
can
be used to mark the relevant subsample.set trace on
to debug programs. That
is a Stata feature that you will want to master.r()
, although we already knew that from
NC-151.tempvar
to place new names in macros, and then use the
contents of the macros as your variable names.
Every one of these 12 features I demonstrated in the context of the mytt
program.
I use these 12 features in nearly every program I write. You will want to master them, and if you mastered no more than these 12, that would not be so bad.
Now that we have caught up, we are ready to talk about saved results. Stata
commands generally return the results of calculations in r()
—or sometimes e()
or s()
, but we'll get to that later. Returned results are
important because they allow us to use Stata commands as subroutines in the
programs we write. In fact, we did exactly that in mytt
when we used the summarize
command.
. summarize mpg
Variable | Obs Mean Std. Dev. Min Max ---------+----------------------------------------------------- mpg | 74 21.2973 5.785503 12 41. return list
scalars: r(N) = 74 r(sum_w) = 74 r(mean) = 21.2972972972973 r(Var) = 33.47204738985561 r(sd) = 5.785503209735141 r(min) = 12 r(max) = 41 r(sum) = 1576
summarize
saves all sorts of things, and we used r(N)
, r(mean)
, and r(Var)
in mytt
. Doing that saved
us from having to write code to calculate the number of observations, mean, and
variance.
When we write a new program, it should save its results in r()
. Our command might produce a pretty display for
end-user use, but if it also saves its results, we can quietly
run the new command and use those results in future
programs.
Saving results is not hard. To save results in r()
,
rclass
option to the program
statement.return
statements in the body of our
program that return what we want to return.Here is an artificial example:
program example, rclass
return scalar x = 1
end
Try it:
. example
. ret list
scalars: r(x) = 1
It is instructive to omit the rclass
option and the
return
from this example. Let's begin by forgetting
to specify the rclass
option,
. program example2
1. return scalar x = 2 2. end. example2
non r-class program may not set r() r(151);
If you do not specify option rclass
, you cannot use
return
; if you try to use return
, Stata stops your program. Now let's include rclass
and omit the return
:
. program example3, rclass
1. local junk = 3 /* just so program has something to do */ 2. end. example3
. ret list
. _
If you specify option rclass
but do not use return
in the body of your program, r()
is cleared. That is not an error, although it may not
be what you intended. By specifying rclass
, you said
your program returns results in r()
, and then, by not
using return
, you simply returned nothing.
This holds some surprises, however, so let me show you. Consider the following two programs:
program example4 program example5, rclass
quietly summarize `1' quietly summarize `1'
end end
The only difference between these programs is that example5
is declared to be r-class. I want you to run example4 mpg
and type return list
,
and then run example5 mpg
and type return list
.
. example4 mpg . example5 mpg
. return list . return list
scalars: . _ r(N) = 74 r(sum_w) = 74 r(mean) = 21.2972972972973 r(Var) = 33.47204738985561 r(sd) = 5.785503209735141 r(min) = 12 r(max) = 41 r(sum) = 1576
Understand what just happened. example5
was declared
to be r-class but did not have any return
statements;
it returned nothing. example4
was not declared to be
r-class, but it did return something. It returned what the last command coded
in it, summarize
, returned.
Why? It is not correct to say that non–r-class programs return nothing.
Non–r-class programs return whatever results happen to be lying around in
r()
at the time the program concludes. example4
ran summarize
and left
behind the results from summarize
. We explicitly told
Stata that example5
was r-class, on the other hand, so
Stata went to extra work to distinguish the results returned by commands inside
example5
from the returned results of example5
itself.
Now I want to show you another variation on example5
.
I will put the original, example5
, on the left and the
new version, example6
, on the right:
program example5, rclass program example6, rclass
quietly summarize `1' quietly summarize `1'
end return add
end
The new statement I coded is return add
. Now, if you
run example6
, results will be the same as those from
the summarize
:
. example6 mpg
. return list
scalars: r(N) = 74 r(sum_w) = 74 r(mean) = 21.2972972972973 r(Var) = 33.47204738985561 r(sd) = 5.785503209735141 r(min) = 12 r(max) = 41 r(sum) = 1576
return add
is how r-class commands add all the
returned results from another Stata command to their returned results.
Bear with me—I have two more things to show you, and then I will explain.
First, let me emphasize that return add
really is an
add,
program example7, rclass
return scalar before = 1
/* <-- new */quietly summarize `1'
return add
return scalar after = 2
/* <-- new */end
. example7 mpg
. return list
scalars: r(after) = 2 <-- note the new r(after) r(sum) = 1576 r(max) = 41 r(min) = 12 r(sd) = 5.785503209735141 r(Var) = 33.47204738985561 r(mean) = 21.2972972972973 r(sum_w) = 74 r(N) = 74 r(before) = 1 <-- note the new r(before)
and finally, I want to show you
program example8, rclass
return scalar before = 1
quietly summarize `1'
return add
return scalar after = 2
quietly summarize weight
/* <-- new */end
Look carefully at this program—the last statement does a summarize weight
. If this program was not explicitly
declared to be r-class, the result of that would be to leave in r()
the returned values from summarize
weight
. This program is r-class, however, and we did not say to return
those values. Anyway, here is the result of running it:
. example8 mpg
. return list
scalars: r(after) = 2 <-- r(after) r(sum) = 1576 ---------------------- r(max) = 41 <--| r(min) = 12 <--| r(sd) = 5.785503209735141 <--| r() from r(Var) = 33.47204738985561 <--| -summarize `1'- r(mean) = 21.2972972972973 <--| r(sum_w) = 74 <--| r(N) = 74 ---------------------- r(before) = 1 <-- r(before)
The extra summarize weight
at the end of program did
not corrupt what our program returned in r()
. The
results of running example8
are the same as those from
running example7
.
Let me summarize this:
rclass
option on the program
statement.r()
whatever is left behind by the last command the program
ran that returned something in r()
.r()
just those things specified by the return
statement(s). There is no exception to this
rule.return
statements can be coded anywhere in the
program. They can be placed at the first line, last line, or any line between.
Scalars, macros, and matrices:
program what, rclass
return scalar x=2+2
return local y=3+2
return local txt "this is a text string"
matrix A = (1,2\3,4)
return matrix mymat A
end
. what
. return list
scalars: r(x) = 4 macros: r(txt) : "this is a text string" r(y) : "5" matrices: r(mymat) : 2 x 2
The only thing you need to know about this is that return
matrix mymat A
returns the matrix by stealing it. When Stata executes
the return matrix mymat A
statement, it does not copy
the matrix but moves it. The result is that matrix A in the program no longer
exists, but there is still a way of referring to it, and we will get to that.
The return scalar
and return
local
commands follow the same rules as the scalar
and local
commands.
There are only two more issues: referring to a returned quantity (1) in another program and (2) in the program that does the returning.
We have already used returned results. In mytt
we
used r(N)
, r(mean)
, and r(Var)
set by summarize
. Using
returned results is the same, whether they are from summarize
, tabulate
, or one of your
own r-class programs. Here are the rules:
r(name)
. You can use r(name)
in any context in which you can use a
scalar.`r(name)'
, and you can use `r(name)'
in any
context.
A returned matrix is referred to as r(name)
, and you can use r(name)
in almost any context in which you can refer to a matrix.
So, we could write
program myprog
what
display "returned x + 1 = " r(x)+1
display "returned y + 1 = " `r(y)'+1
display `"returned txt is "`r(txt)'""'
display _n "Here is returned matrix mymat*mymat':"
matrix B = r(mymat)*r(mymat)'
mat list B
end
. myprog
returned x + 1 = 5 returned y + 1 = 6 returned txt is "this is a text string"
Here is returned matrix mymat*mymat':
symmetric B[2,2] r1 r2 r1 5 r2 11 25
Also, another set of rules is sometimes handy:
r(name)
and r(name)
is
not defined, then missing value is returned.`r(name)'
and `r(name)
'
is not defined, then "" (an empty string) is substituted.r(name)
and are used in expressions. If, however, you
refer to `r(name)'
—which you can use in any
context—the printed form of the scalar is substituted.`r(name)'
and can be used in any context. If, however,
you refer to `r(name)'
in an
expression context, a string is returned.
Rules 4 and 5 turn out to be very useful, rule 6 is sometimes useful, and I have never yet found a use for rule 7.
Rule 4 means that, if you write a program that returns scalars r(mean)
and r(Var)
, and if the
results cannot be calculated, you can arrange your code to save missing value
in r(mean)
and r(Var)
, or you
can just not bother to set them at all. It will make no difference to the
consumer of your returned results because, either way, r(mean)
and r(Var)
will be missing.
Rule 5 is the same as rule 4 for strings. If your program is supposed to
return in r(title)
the title, and the title is
nothing, you can either set r(title)
to contain
nothing or not bother to set the r(title)
at all.
Rule 6 does not affect how you write programs that return results, but it is
useful when you write programs that need to pass returned results to other
programs. For instance, I have just used summarize
to
obtain r(mean)
. I need to pass the calculated mean to
a subroutine I have written, but that subroutine expects that I am going to
pass the mean as a literal number. I can code `r(mean)'
as its argument. (See Exercise
2.)
Rule 7 is the mirror image of Rule 6, which is why it's there, but I've discovered no use for it.
If you are writing a program that returns results, distinguish carefully
between the results you will return and the results other programs return to
you as you are making your calculations. For instance, perhaps your program
will return r(mean)
—the mean of
something—and in the process of making the calculation, you need to use
the r(mean)
returned by summarize
of some other variable.
r()
always refers to results returned to you by some
other program. Thus r(mean)
is the value returned by
some program you call—it is not the value you will return.
Stata has another function, return()
, to refer to the
values you will return—the values that ultimately will work their way
into r()
when your program concludes.
For instance, consider the following code:
program randr, rclass
return scalar mean = 3
qui summarize mpg
return scalar sum = return(mean)+r(mean)
end
This program is artificial, but pretend that the first line is really some complicated block of code that resulted in the value you wanted to return for mean, the second line some long second calculation, and the third line a long calculation where you needed to combine the results of the first two blocks of code.
In any case, the code actually says
return scalar mean = 3
When my program concludes, I want r(mean)
to be 3.
Stata does not set r(mean)
to 3 right now. Stata
actually sets return(mean)
to 3, and then later when
your program concludes, Stata will copy what is in return()
into r()
.
qui summarize mpg
Run summarize
right now:
return scalar sum = return(mean)+r(mean)
Just as with the first line, this line does not set r(sum)
. It sets return(sum)
. In
return(sum)
it puts the sum of r(mean)
— which is what summarize
just returned—plus return(mean)
, the value stored in the first line.
So, Stata executes those three lines, and then your program ends. When your program ends, Stata does the following:
r()
return()
into r()
When you write your program, the rules for referring to return(name)
are the same as those
for referring to r(name)
.
As an example, let's go back to mytt
. No, you do not
have to look up the code. Just recall that, as a result of the exercises at
the end of Lecture 3, we made an immediate version
of mytt
called mytti
. In
that program, we had the following subroutine:
program tt_1i
args n xbar s eqsign mu
local t = (`xbar'-`mu')*sqrt(`n')/`s'
di "t(" `n'-1 ") = " `t'
end
Let us assume we wish to turn this subroutine into an r-class subroutine that
returns in r(t)
the t-statistic and in r(df)
the degrees of freedom. One way we could do that
would be
program tt_1i, rclass
args n xbar s eqsign mu
local t = (`xbar'-`mu')*sqrt(`n')/`s'
di "t(" `n'-1 ") = " `t'
return scalar t = `t'
return scalar df = `n' - 1
end
Using the return()
function, however, our program can
be a little shorter:
program tt_1i, rclass
args n xbar s eqsign mu
return scalar t = (`xbar'-`mu')*sqrt(`n')/`s'
return scalar df = `n' - 1
di "t(" return(df) ") = " return(t)
end
Note that in the last line I changed
di "t(" `n'-1 ") = " `t'
to read
di "t(" return(df) ") = " return(t)
and not
di "t(" r(df) ") = " r(t)
I had previously said to return
scalars t and df.
That means they will be in r()
when my program
ends—when my caller gets back control—but they are not there yet.
While my program is still running, those two results are stored in return()
, the values to be returned. return(df)
is the df value I previously set, and return(t)
is the t value.
Do not let this confuse you: while the tt_1i
subroutine is active, the return values are return(t)
and return(df)
. Once tt_1i
completes, the returned values are r(t)
and r(df)
. Thus, inside the tt_1i
program, I coded return(df)
and return(t)
to refer to the values I will be returning.
Most Stata programs return values in r()
, but there
are two other places Stata programs could return values: s()
and e()
.
First, understand that a Stata program exclusively returns values in r()
, s()
, or e()
; it never returns values in any combination of the two
or all three.
Programs that return values in s()
are said to be
s-class, and programs that return values in e()
are
said to be e-class. e-class refers to the estimation class, and we are going
to say a lot about estimation commands in this lecture, so let's put that one
aside right now.
s-class is a really strange little-class, but it is designed to handle an important problem. Imagine that you are designing a program and that a user types something like
. myprog 5 (means) mpg weight (medians) displ if weight<r(mean)
I'm not going to explain what the 5
means, or the
(means)
or (medians)
, because I do not know myself.
I am just trying to show something that is a parsing nightmare.
Whatever the general syntax of this command, you are going to have to write custom code to parse it, and if you follow my recommendation that good code uses lots of subroutines, that means you will write subroutines to assist in parsing this syntax.
Look at the if condition I put on the end of the example:
. myprog 5 (means) mpg weight (medians) displ if weight<r(mean)
^^^^^^^^^^^^^^^^^
The user wants to restrict the calculations of myprog
to the subsample for which weight<r(mean)
, and
we'll assume, she issued some command before the myprog
command that put into r(mean)
whatever it is she wanted.
Now, since this if condition is at the end of the line and since the command has
nonstandard syntax, you are going to have to execute a fair amount of code
before your program even identifies that if weight<r(mean)
is the if
condition. Assuming you follow my recommendation and use lots of subroutines in
that process, you are in for trouble.
You are going to want your parsing subroutines to return things, so say that
you return results in r()
. By the time you actually
find the if weight<r(mean)
that the user
typed—and evaluate it—you will have changed what is in r()
. r(mean)
will not mean the
same thing it did at the time the user typed it.
To avoid that, you should have your parsing routines return results in
s()
, not r()
. To create an s-class subroutine,
sclass
option to the program
statement.sreturn
statements in the body of your program
that return what you want to return.s-class differs from r-class in that it contains only macros, not scalars or matrices, neither of which you need for parsing. Remember, numbers can be returned in macros.
The caller consumes what you return by referring to `s(name)'
.
If you need to refer to a previously sreturned result in the body of the
program doing the sreturning, you refer to `sreturn(name)'
.
As an example, let's imagine that I am writing a subroutine to help parse
. myprog 5 (means) mpg weight (medians) displ if weight<r(mean)
and that one of the routines is
CheckPar "thing"
Subroutine CheckPar looks at thing
and determines if it is
(means)
or (medians)
. If it is not either of these,
it sreturns s(type)
containing 0. If it is means, it
sreturns 1, and if it is medians, it sreturns 2. Of course, if there are
problems, it produces an error:
program CheckPar, sclass
args token
if substr(`"`token'"',1,1) != "(" {
sreturn local type 0
}
else if `"`token'"'=="(means)" {
sreturn local type 1
}
else if `"`token'"'=="(medians)" {
sreturn local type 2
}
else {
display as error `""`token'" invalid"'
exit 198
}
end
e-class refers to the estimation class. As you might suspect, to create an e-class command,
eclass
option to the program
statement.ereturn
statements in the body of your program
that return what you want to return.I will write a lot about e-class, but I just want you to first understand the mechanics of it.
e-class really is different from r-class but more than anything in how it is
used. For instance, unlike r-class results, e-class results tend to stick
around for a long time—until you run the next estimation command—but
that is solely because that by convention only estimation commands save results
in e()
. If some program violated that convention, the statement would no
longer be true.
e-class appears to have a lot of structure to it—e(cmd)
is the name of the last estimation command, e(ll)
the log-likelihood value, e(b)
the coefficient vector, e(V)
the variance matrix, and so on—and some of that is due to convention. We
agree that when you write an estimation command, you will store the the name of
your command in e(cmd)
—and some of that is due
to the oddities of the-class itself.
Actually, the only real oddity of the-class is that the first thing you post in
e()
must be done with the ereturn
post
command, and that command requires you to specify coefficient
vector, variance matrix, and a variable that marks which observations were
used. After that, e-class works like r-class, except that you save other
results using ereturn local
rather than return local
, ereturn scalar
rather
than return scalar
, and ereturn
matrix
rather than return matrix
. What is
stored is all convention, but there's a lot of convention.
Before we get to writing an e-class command, let's begin by using results from e-class commands.
After you estimate model parameters, you can use a postestimation command with an estimation command to explore the estimates. This means that you will need to access information and results about the estimated model, and I want to show you how to do that.
We wrote our first postestimation command in Exercise 4 of Lecture
3. predexp
created newvar containing the
predictions of the mean y after a regression of ln(y). The code for this was
program predexp
syntax newvarname [if] [in]
tempvar new
quietly {
local s2 = e(rmse)^2
tempvar pred
predict double `pred' `if' `in'
gen `typlist' `new' = exp(`pred')*exp(`s2'/2)
rename `new' `varlist'
}
end
The purpose of this exercise was twofold. Related to the last lecture, you had
to deal with the programming complication of creating a new, permanent
variable. Related to this lecture, the exercises showed that Stata estimation
commands save results—regress saved what we needed in e(rmse)
—and that you can discover where results are stored by looking at the "Saved
results" section in
[R] regress
(or by typing ereturn list
).
Let me tell you the few things you can absolutely depend on an estimation command to store:
e(cmd)
contains the name of the estimation
command.e(b)
and e(V)
contain the entire coefficient vector (stored as a row) and the
variance–covariance matrix of the estimators. Also, you can use _b[name] and _se[name] to access the
coefficients and their standard errors. For instance, in some program you
might code local t = _b[mpg]/_se[mpg]
. These two
elements of Stata's language just reach inside e(b)
and e(V)
.e(sample)
contains 1 if the observation
was used in estimation and 0 otherwise.Let me show you:
. regress mpg weight displ
output omitted. display "`e(cmd)'"
regress. mat list e(b)
e(b)[1,3] weight displ _cons y1 -.00656711 .00528078 40.084522. mat list e(V)
symmetric e(V)[3,3] weight displ _cons weight 1.360e-06 displ -.0000103 .00009741 _cons -.00207455 .01188356 4.0808455. display _b[displ] " " _se[weight]
.00528078 .00116624. count if e(sample)
74
In addition to e(cmd)
, e(b)
, e(V)
, and e(sample)
,
estimation commands may store more information such as macros, scalars, or
matrices. For instance, if you look under "Saved results" in
[R] regress,
you will see that regress
saves the name of the
dependent variable in macro e(depvar)
. Most
estimation commands do that, but it is not guaranteed.
A postestimation command is, therefore, a command that uses any of the above pieces. There are lots of postestimation commands in Stata, and it is worth reviewing just a few of them and how they were written.
test
This command tests linear constraints about the coefficients, the required
information being the coefficients and VCE matrix. test
accesses
e(b)
and e(V)
.
predict
This command calculates predicted values, residuals, and the like. Obviously,
it accesses e(b)
and, for some calculations, e(V)
. In addition, because predict
will do special things for special estimation commands (such as calculate
probabilities in the case of logistic
), it must look
at `e(cmd)'
.
estat gof
This command performs a goodness-of-fit test after logit
or logistic
.
Writing your own postestimation command is just a matter of knowing what you are going to program and opening the manual to "Stored results" of the estimation command to determine where the ingredients of the calculation are stored.
It is vitally important that, if your postestimation command is for use after
the XYZ command, you ensure that it works only after the XYZ command. You do
not want the user accidentally using your command after ABC, mistakenly
thinking that their previous model is XYZ and obtaining results that could be
misinterpreted. It would, for instance, cause problems if estat gof
, a command for use after logit
or logistic
, actually did
something after regress
. In fact, it does not:
. regress mpg weight displ
output omitted. estat gof
invalid subcommand gof r(321);
That is what a postestimation command is supposed to do when misused. The
invalid subcommand gof
message does not mean there are no estimates stored;
it means only that the stored estimates are not appropriate for this command.
How does estat
do this? Each estimation command has
an ereturn
value e(estat_cmd)
. This macro contains the name of the estat
handler function. An estat
handler function defines the command-specific actions
that estat
is to perform after an estimation command.
For example, suppose we created an estimation command mylogit
that returned the ereturn value mylogit_estat
in the macro e(estat_cmd)
.
program define mylogit, eclass
logit `0'
ereturn local cmd "mylogit"
ereturn local estat_cmd "mylogit_estat"
end
Next, we would create our estat
handler function
mylogit_estat.ado which would look something like
*! version 1.0.0 11 Jun 2007
program mylogit_estat, rclass
version 10
if "`e(cmd)'" != "mylogit" {
error 301
}
gettoken key rest : 0, parse(", ")
if `"`key'"' == "gof" {
gof `rest'
}
else {
estat_default `0'
}
end
program gof, rclass
display "here I am"
end
Note: We strongly recommend naming the handler cmd_estat, where cmd is the name
of the estimation command. Also, we used the gettoken
command in mylogit_estat to remove the 'gof' from what was passed to
mylogit_estat and put the rest of the command line in the macro 'rest'. We'll
explain more about gettoken
in lecture 5.
Now let's try our new postestimation command.
. sysuse auto, clear
(1978 Automobile Data). mylogit for mpg
Iteration 0: log likelihood = -45.03321 Iteration 1: log likelihood = -39.380959 Iteration 2: log likelihood = -39.288802 Iteration 3: log likelihood = -39.28864 Logistic regression Number of obs = 74 LR chi2(1) = 11.49 Prob > chi2 = 0.0007 Log likelihood = -39.28864 Pseudo R2 = 0.1276 ------------------------------------------------------------------------------ foreign | Coef. Std. Err. z P>|z| [95% Conf. Interval] -------------+---------------------------------------------------------------- mpg | .1597621 .0525874 3.04 0.002 .0566927 .2628316 _cons | -4.378866 1.211289 -3.62 0.000 -6.752949 -2.004783 ------------------------------------------------------------------------------. ereturn list
scalars: e(N) = 74 e(ll_0) = -45.03320955699139 e(ll) = -39.2886400826789 e(df_m) = 1 e(chi2) = 11.489138948625 e(r2_p) = .1275629592210724 e(N_cdf) = 0 e(N_cds) = 0 macros: e(estat_cmd) : "mylogit_estat" e(cmd) : "mylogit" e(title) : "Logistic regression" e(depvar) : "foreign" e(crittype) : "log likelihood" e(predict) : "logit_p" e(properties) : "b V" e(chi2type) : "LR" matrices: e(b) : 1 x 2 e(V) : 2 x 2 e(rules) : 1 x 4 functions: e(sample). estat gof
here I am
In the above example estat
knew which handler to call
because of the ereturn
value e(estat_cmd).
The estat
handler function gets called from the estat
command using the following code.
if `"`e(estat_cmd)'"' != "" {
`e(estat_cmd)' `0'
return add
exit
}
In our estat
handler we
check to see if the first token `1'
is equal to "gof"
if `"`1'"' == "gof" {
gof `0'
}
and, if not, use the default estat
command.
else {
estat_default `0'
}
Also, at the beginning of your estat
handler function you should have lines that read
if "`e(cmd)'" != "mylogit" {
error 301
}
Every estimation command sets its identity in `e(cmd)'
, and all you have to do is verify that the macro
contains what you expect. (See Exercise 3.)
Important: postestimation commands are not e-class. Only the estimation commands themselves are e-class. A postestimation command is probably r-class.
Writing a postestimation command requires no special skills—all you need to know is where the postestimation results are.
Writing an estimation command, you might suspect, is more of an undertaking. After all, as you just learned, all sorts of things have to be cleared and stored, and you are probably worried that just the housekeeping details will be a nightmare.
As it turns out, that is not true. Writing an estimation command can be an undertaking but only because of the inherent complication of the estimation formula itself. The housekeeping details almost take care of themselves once you understand their logic.
Below, we are going to explore two types of estimation commands:
All estimation commands have the same outline:
program XYZ, eclass
if !replay() {
/* estimation logic */
ereturn local cmd "XYZ"
}
if "`e(cmd)'" != "XYZ"{
error 301
}
/* logic to display results */
end
The replay()
function is new, but let's pass over
that. replay()
returns true if the user types nothing
after XYZ and false otherwise. I'll explain the details later. Anyway, in the
outline I use !replay()
, so the estimation logic is
executed if the user types something after XYZ and skipped otherwise.
There are lots of variations on this outline, but they all provide the ability to redisplay results.
e(cmd)
is set to contain the name of the estimation command,
and results are then displayed.e(cmd)
are checked to ensure they contain the name of
the estimation command, and results are (re)displayed.
Setting and checking e(cmd)
ensures that our command
redisplays results only when it should—that is, when the estimation
results are produced by our command. All estimation commands follow the e(cmd)
convention. Consider the following session:
. XYZ price mpg weight
. XYZ
. logistic foreign mpg weight
. XYZ
XYZ price mpg weight
executes our estimation command,
which produces results and displays them. Along the way, it sets e(cmd)
to contain XYZ
. Thus the subsequent
XYZ
finds that e(cmd)
contains
XYZ
and displays the results again.
logistic foreign mpg weight
executes the logistic
regression estimation command, which produces results and displays them. Along
the way, logistic
sets e(cmd)
to contain "logistic". The XYZ
following logistic
thus finds that e(cmd)
does not contain XYZ
and so issues the last estimates not found
error.
As long as every estimation command follows the e(cmd)
convention, all works well. In fact, things are even safer than that because
Stata itself clears everything in e()
when estimation
results are saved.
I said above that lots of variations on the code outline are possible, and one variation I prefer looks like this:
program XYZ
if replay() {
if "`e(cmd)'" != "XYZ" {
error 301
}
}
else {
/* estimation logic */
ereturn local cmd "XYZ"
}
/* logic to display results */
end
I have reordered statements physically, but if you go through them logically,
you will find the result is the same. (There is one minor difference, the
contents of e(cmd)
are no longer checked when we enter
the play back logic from the estimation logic.)
I prefer this version of the outline because it is a little (and only a little) easier to parse options.
It is not really true that anything following the name of an estimation command
is a request for estimation. All Stata estimation commands allow the level(#)
option to specify the width of the confidence
interval for the coefficients, and you can specify that when you playback
results or when you estimate them. Thus,
. XYZ, level(90)
is not a request that results be estimated but a request that results be redisplayed with 90% confidence intervals. Our estimation program should be able to handle this.
Here is how I add the level(#)
option to the outline:
program XYZ
local options "Level(cilevel)"
<- newif replay() {
if "`e(cmd)'" != "XYZ" {
error 301
}
syntax [, `options']
<- new}
else {
syntax ... [, ... `options']
... /* estimation logic */ereturn local cmd "XYZ"
}
/* logic to display results */end
Now let me explain the replay()
function. replay()
looks at `0'
—what
the user types following the command. If `0'
is empty
(meaning the user typed nothing) or starts with a comma (meaning the user typed
just options), replay()
returns true, and otherwise it
returns false. This is equivalent to coding
if replay() {
We could code
if (`"`0'"'=="" | substr(`"`0'"',1,1)==",") {
but coding if replay()
is easier. Before going deeper
into this code, let me explain the problems the new lines in the code were
added to address:
level(#)
option when results are redisplayed. The
user could type XYZ
or XYZ,
level(90)
.level(#)
option when results are estimated. The user
could type XYZ mpg weight, level(90)
.regress
command, that a user can specify only at the time of
estimation. The user can type regress mpg weight,
nocons
but not regress, nocons
. The constant
cannot be removed after estimation. There may be similar options for our XYZ
command.Said differently,
level(#)
.nocons
.There are no options that can be specified at playback but not estimation because, by definition, playback is a subset of estimation.
To understand how I parsed this, look at the two new features at the top of the outline:
program XYZ
local options "Level(cilevel)"
<- newif replay() {
...
syntax [, `options']
}
else {
syntax ... [, ... `options']
<- new...
}
...
end
I hope the cilevel
is not confusing you. If it is, pretend that the
outline read
program XYZ
local options "Level(integer 95)"
<- newif replay() {
...
syntax [, `options']
}
else {
syntax ... [, ... `options']
<- new...
}
...
end
The cilevel
option descriptor requires the user to
specify a valid level for a confidence interval. If the user does not specify
this option, the default level is obtained from c(level)
and stored in the macro `level' The c-class object
c(level)
probably contains 95 (c-class objects are
where Stata stores system parameters and constants). It contains the default
significance level, which is 95, unless the user resets it using the set level
command. I have never yet met a user who did.
It is important that in local macro options I put the options to be allowed both at playback and estimation time. In this example, we must first learn how to define estimation results. I'm not talking about the complexities of the estimation itself; I'm talking about what we do with the results once we have them.
This way, if I want to add a new playback option, I can add it at one place in
the code (the local options
statement), and it will
affect both syntax
statements.
For instance, cox
allows an hr
option to display results as hazard ratios. It does not
affect estimation; it just affects how results are displayed. If I wanted to
add this option to my program, I would change
local options "Level(cilevel)"
to
local options "Level(cilevel) HR"
As I said, there are multiple ways to express the same logic in a program. Here is yet another outline that is logically equivalent but perhaps clearer:
program XYZ
if replay() {
Playback `0'
}
else Estimate `0'
end
program Estimate
syntax ... [, ...]
/* estimation logic goes here */ereturn local cmd "XYZ"
Playback, level(`level')
end
program Playback
syntax [, ...]
if "`e(cmd)'" != "XYZ" {
error 301
}
/* logic to display results goes here */end
This formulation of the outline is neither better nor worse than the previous one; I have used all three in my own work, and others to boot. With this outline, options common to estimation and playback must be coded twice—which is a disadvantage—but in return, the separation of estimation and playback is made clearer.
Now that we have an outline for an estimation command, let's fill one in.
First, we must learn how to define estimation results. I'm not talking about the complexities of the estimation itself but about what we do with the results once we have them.
It turns out that storing the initial results is easy and that, once posted, results can be easily displayed, too.
So, let's put aside calculating the estimates and pretend we already have them. What would we do with them?
Pretend that somehow, for some estimation problem, we came up with the coefficient vector bhat=(−, −.1685, 3.907, 13.70) and corresponding var(b) (synonyms: variance–covariance matrix; VCE):
.0084 .0706 -.3840 .0706 1.023 -4.321 -.3840 -4.321 20.41
To show you what we would do if we had them, let me first define the matrices I've just displayed:
. mat bhat = (-.1685, -3.907, 13.70)
. mat vce = ( .0084, .0706, -.3840 \
.0706, 1.023, -4.321 \
-.3840, -4.321, 20.41)
You can read about Stata's matrix commands for yourself (see [P] matrix and [M] Mata). I have just copied the numbers into Stata. In an estimation command, these matrices would presumably have been produced by formula.
I will tell you now that these results correspond to coefficients on the variables mpg, weight, and _cons. I am going to label the rows and columns of my vector and matrix with these names:
. mat colnames bhat = mpg weight _cons
. mat rownames vce = mpg weight _cons
. mat colnames vce = mpg weight _cons
All I have done so far is to make pretty Stata matrices:
. mat list bhat
bhat[1,3] mpg weight _cons r1 -.1685 -3.907 13.7. mat list vce
symmetric vce[3,3] mpg weight _cons mpg .0084 weight .0706 1.023 _cons -.384 -4.321 20.41
So, I now have pretty matrices. Earlier we asked, "So, let's put aside calculating the estimates and pretend we already have them. What would we do with them?" Okay, we have matrices bhat and vce. What do we do with them? Given that you have a matrix named bhat that contains coefficients, and matrix vhat containing the corresponding VCE, you type
. ereturn post bhat vce
to post them as official estimation results. That one little command, ereturn post bhat vce
, performs a miracle. After giving it,
you will find that the matrices bhat and vce are gone:
. mat list bhat
bhat not found r(111);. mat list vce
vce not found r(111);
Stata ate them. Those matrices are now official estimation results of Stata. Stata has another command to display official estimation results:
. ereturn display
-----------------------------------------------------------------------------
| Coef. Std. Err. z P>|z| [95% Conf. Interval]
---------+-------------------------------------------------------------------
mpg | -.1685 .0916515 -1.838 0.066 -.3481337 .0111337
weight | -3.907 1.011435 -3.863 0.000 -5.889375 -1.924625
_cons | 13.7 4.517743 3.032 0.002 4.845387 22.55461
-----------------------------------------------------------------------------
Note the nicely formatted output. All I did to produce it was type ereturn display
. It has test statistics, confidence
intervals, everything.
If you explore Stata's postestimation commands, you will find that the ones that ought to work do work. For instance,
. test 10*mpg = weight
( 1) 10.0 mpg - weight = 0.0
chi2( 1) = 10.95
Prob > chi2 = 0.0009
Keep playing, and you will discover that predict
and
other commands work and that all the standard features such as _b[name]
and _se[name]
work, too.
. display _b[weight]
-3.907
Remember when Stata ate our b and v matrices? That's okay; if we need them back, we can type
. mat bhat = e(b)
. mat vce = e(V)
. mat list bhat
bhat[1,3] mpg weight _cons y1 -.1685 -3.907 13.7
So how do you create an estimator? Produce the coefficient vector and VCE,
and then ereturn post
them.
So, let's write an estimation command. Let's pretend that Stata had no regress
command and that we needed to write linear
regression. The matrix formulas are
-1 b = (X'X) X'y 2 -1 var(b) = s (X'X) 2 s = (y'y - b'X'y)/(n-k) n = number of observations k = number of independent variables
Here is the complete Stata code:
| ADO-FILE:linreg.ado |
|---|
|
Here is an example of linreg
in use:
. linreg price weight mpg
(obs=74)
-----------------------------------------------------------------------------
| Coef. Std. Err. t P>|t| [95% Conf. Interval]
--------+--------------------------------------------------------------------
weight | 1.746559 .6413538 2.723 0.008 .4677361 3.025382
mpg | -49.51222 86.15604 -0.575 0.567 -221.3025 122.278
_cons | 1946.069 3597.05 0.541 0.590 -5226.244 9118.382
-----------------------------------------------------------------------------
If you type linreg
without arguments, it will
redisplay results. linreg
is a full-fledged Stata
estimation command.
Here are my comments on the code:
matrix accum
forms cross-product matrices, Z'Z. I passed matrix
accum
the entire varlist, which is to say, the dependent variable followed
by the list of independent variables. Think of this as Z=(y X). Thus, Z'Z = (y
X)'(y X), or the matrix
y'y y'X X'y X'X
You will want to read about ereturn post
. I used the
esample()
option to specify which observations were
involved in the estimation. This sets up the e(sample)
function. A common error in first drafts of an
estimation command program is failing to set esample()
. If you do not set esample()
, statements like
summarize price if e(sample)
will not work as expected (for example, it will produce summary results using
zero observations). I also used the obs()
option to
specify the number of observations and the dof()
option to specify the residual degrees of freedom. The result of the dof()
option is that ereturn
display
produced t- rather than Z-statistics.
This program is not perfect; in particular, it does not handle dropped variables correctly because it says
local k = rowsof(`XX')
Some of the rows of `XX'
might be "empty"; see Exercise
4.
Do not forget the ordering of the statements:
ereturn post `b' `V', dof(`df') obs(`n') esample(`touse')
ereturn local cmd "linreg"
It would be wrong—and it would not work—if we reversed the order:
ereturn local cmd "linreg"
ereturn post `b' `V', dof(`df') obs(`n') esample(`touse')
When you ereturn post
, Stata clears all previous
estimation results, deleting everything in e()
. The
reversed-order lines would set e(cmd)
, but the ereturn post
would then clear e(cmd)
so that it contained nothing.
The right order is
ereturn post `b' `V', dof(`df') obs(`n') esample(`touse')
ereturn local cmd "linreg"
Also, when you define e(cmd)
, estimation results are
considered official, so if you set other things in e()
, set them after the ereturn
post
and before the ereturn local cmd
. If our
program wanted to retain the value of s2 for later display or for use by a
postestimation command, the correct way to do that would be
ereturn post `b' `V', dof(`df') obs(`n') esample(`touse')
ereturn scalar s2 = ...
ereturn local cmd "linreg"
In other words
ereturn post
.e()
to things other than e(cmd)
.e(cmd)
.
This way, if the user presses Break between 1 and 3, Stata knows the
results are incomplete because e(cmd)
has not been set.
You now know how to post b and V, the coefficients, and VCE, as official
estimation results, and that means you now know enough to write maximum-
likelihood estimation commands, although it would be an undertaking if you did
not use Stata's ml
to perform the maximization. No
matter how you produce b and V, you could write the code necessary to maximize
a likelihood function. You will find it easier, however, to master Stata's
ml
.
The estimation command outline for a maximum likelihood estimator is no different from that of any other estimation command:
program XYZ
local options "Level(cilevel)"
if replay() {
if "`e(cmd)'" != "XYZ" {
error 301
}
syntax [, `options']
}
else {
syntax ... [, ... `options']
/* estimation logic */ereturn local cmd "XYZ"
}
/* logic to display results */end
For instance, pretend that Stata did not have a logistic regression command. Here is a perfectly serviceable alternative:
| ADO-FILE:logisreg.ado |
|---|
|
| ADO-FILE:logis_ll.ado |
|---|
|
I have comments to make on these programs, but first, let me show you that they work:
. logisreg for mpg weight
initial: log likelihood = -51.292891 alternative: log likelihood = -46.081697 rescale: log likelihood = -45.181365 Iteration 0: log likelihood = -45.181365 Iteration 1: log likelihood = -29.420506 Iteration 2: log likelihood = -27.229801 Iteration 3: log likelihood = -27.175287 Iteration 4: log likelihood = -27.175156 Iteration 5: log likelihood = -27.175156 my logistic. logisreg
Number of obs = 74 Wald chi2(2) = 17.78 Log likelihood = -27.175156 Prob > chi2 = 0.0001 ----------------------------------------------------------------------------- foreign | Coef. Std. Err. z P>|z| [95% Conf. Interval] --------+-------------------------------------------------------------------- mpg | -.1685869 .0919175 -1.834 0.067 -.3487418 .011568 weight | -.0039067 .0010116 -3.862 0.000 -.0058894 -.001924 _cons | 13.70837 4.518709 3.034 0.002 4.851859 22.56487 -----------------------------------------------------------------------------
Later, if I type logisreg
without arguments,
. logisreg
my logistic Number of obs = 74
Wald chi2(2) = 17.78
Log likelihood = -27.175156 Prob > chi2 = 0.0001
-----------------------------------------------------------------------------
foreign | Coef. Std. Err. z P>|z| [95% Conf. Interval]
--------+--------------------------------------------------------------------
mpg | -.1685869 .0919175 -1.834 0.067 -.3487418 .011568
weight | -.0039067 .0010116 -3.862 0.000 -.0058894 -.001924
_cons | 13.70837 4.518709 3.034 0.002 4.851859 22.56487
-----------------------------------------------------------------------------
Now for my comments:
logisreg
followed the same outline as any
estimation command.ml
command; see [R] ml to learn more about this command, or much
better, see the book Maximum Likelihood Estimation
with Stata.ereturn post
to
postestimation results. ml
handled that for me.ereturn local cmd "logisreg"
after the
ml
statement.I did not type
ereturn display
to display final estimation results, although I could have. I typed
ml display
ml display
displays not only the coefficient table but the
log-likelihood value, too.
logis_ll
, which ml
required that I write (although the name was of my
choosing), is stored in a separate ado-file. I could not store logis_ll
in logisreg.ado because the name logis_ll
would be known only inside my ado-file, and thus
the external ml
programs could not have called it.
mytt
as we last left it in the exercises to Lecture 3 (mytt
is attached
below) to return r(t)
and r(df)
. Remember, mytt
is now
implemented in terms of mytti
, so first fix mytti
to return r(t)
and r(df)
and then fix mytt
to return
those values.
Explain why the following does not work:
. summarize mpg
Variable | Obs Mean Std. Dev. Min Max ---------+----------------------------------------------------- mpg | 74 21.2973 5.785503 12 41. mytti r(N) r(mean) r(sd) = 20
'r' found where integer expected r(7);
Explain why the following does work:
. summarize mpg
[output omitted]. local se = r(sd)
. mytti `r(N)' `r(mean)' `se' = 20
t(73) = 1.9289201
In Exercise 4 of Lecture 2, we wrote predexp
to create a new variable containing the predictions of the mean y after a
regression of ln(y). As such, predexp
was our first
example of a postestimation command. In this lecture, we emphasized that we
should ensure that a postestimation command is not accidentally misused by
verifying that the stored estimates are what they are supposed to be. Since
our command is for use after regress
, the lecture
recommended that we include the code
if "`e(cmd)'" != "regress" {
error 301
}
The predexp
program contains no such lines:
program predexp
syntax newvarname [if] [in]
tempvar new
quietly {
local s2 = e(rmse)^2
tempvar pred
predict double `pred' `if' `in'
gen `typlist' `new' = exp(`pred')*exp(`s2'/2)
rename `new' `varlist'
}
end
What happens if predexp
is misused? Explain.
linreg
has one problem: it does not produce
correct results in the presence of collinear variables. For instance, if you
. generate new = mpg
. linreg price mpg new foreign
the coefficients are correct, but the standard errors, t statistics, significance levels, and confidence intervals are incorrect. This is all caused by the line
local k = rowsof(`XX')
Fix it.
Hint: The problem of collinear variables arises, numerically, when inverse
matrices are calculated: X'X
is not a full-rank
matrix. Stata's invsym()
function is prepared to deal
with such matrices. In the case of a singular matrix, invsym()
drops collinear rows and columns until the matrix
can be inverted. invsym()
returns a matrix that is
physically k × k, but it sets diagonal elements to 0 where the
corresponding variable was dropped. That is, in the lines
local k = rowsof(`XX')
mat `XXinv' = invsym(`XX')
matrix `XXinv'
will be physically k × k but may contain zeros on the
diagonal. For our calculation formulas, k is the number of estimated parameters
(or, the rank of X'X
), meaning the number of nonzero elements on the
diagonal of `XXinv'
.
Hint 2: Find out about the diag0cnt()
function.
Change logisreg
to allow an or
option that would report odds ratios (exponentiated
coefficients) rather than the coefficients themselves. Start with the improved
version of logisreg.ado
.
Hint: Note that ml display
has an eform()
option. Specify option eform(or)
on that statement, and you will have the results
you want. So, now you just have to figure out how to get eform(or)
on that statement when you want it there.
Attached below are
END OF EXERCISES
Attached below are
mytt.ado
mytti.ado
for use with Exercise 1.
| ADO-FILE:mytt.ado |
|---|
|
| ADO-FILE:mytti.ado |
|---|
|


This is your bio, you can edit it by clicking the "edit" button.
Here is the list of projects that you posted.
#taaleruption #taalvolcano #naturalcalamity #volcano #philippines
#panda #SavePandas #SaveAnimals
#BenguetForestFire #ForestFire #fire #NaturalCalamity
Upload Image


The same-origin policy is a critical security mechanism that restricts how a document or script loaded from one origin can interact with a resource from another origin.
Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin, access to selected resources from a different origin.
(For everything else, there's MasterCard CSP)
| URL | Origin | Reason |
|---|---|---|
| http://store.company.com/dir2/other.html | Same | Only the path differs |
| http://store.company.com/dir/inner/another.html | Same | Only the path differs |
| https://store.company.com/page.html | Different | Different protocol |
| http://store.company.com:81/dir/page.html | Different | Different port |
| http://news.company.com/dir/page.html | Different | Different host |
Demo: misconfigured-cors
Demo: no-cors
Demo: cors-cdn
Demo: cors-api
Demo: cors-api-fetch-credentials
Demo: working-example-urlencoded
Origin list: WON'T WORK!!!
Header set Access-Control-Allow-Origin "https://example.com, https://anotherexample.com"
Multiple headers: WON'T WORK!!!
Header set Access-Control-Allow-Origin "http://example.com"
Header set Access-Control-Allow-Origin "https://example.com"
Header set Access-Control-Allow-Origin "http://anotherexample.com"
Header set Access-Control-Allow-Origin "https://anotherexample.com"
Dynamic ACAO: whitelist
Demo: dynamic-whitelisted
origin = request.getHeader("Origin");
regex = "https:\/\/[a-z]+.example.com";
if re.test(origin, regex) {
response.addHeader(origin);
}
https://asdf.example.com
https://asdfxexample.com
https://example.com
https://example.com.attacker.com
Demo: preflight-request
Demo: custom-request-header
Demo: custom-response-header
Demo: custom-response-header-exposed
https://blog.detectify.com/2018/04/26/cors-misconfigurations-explained/ https://www.we45.com/blog/3-ways-to-exploit-misconfigured-cross-origin-resource-sharing-cors https://www.corben.io/advanced-cors-techniques/
https://github.com/RUB-NDS/CORStest https://github.com/lc/theftfuzzer


Monthly expenses are calculated as a percentage (%) of the total rental income. For example with a $1000 rental income, entering in 5 will be an expense of $50.
Utilities: Any utilities that will be paid by the landlord such as water, electricity, gas or oil.
Vacancy: The estimated expense of loss rental income due to vacancy.
Repairs & Maintenance: Smaller repairs needed to keep a property functioning and habitable. The IRS allows maintenance items to be depreciated all in the same year. Examples: Repairing broken fridge or patching leaky roof.
CapEx: CapEx or Capital Expenditures are larger items that increases the value of the property or extends its life. The IRS requires CapEx to be depreciated over the useful lifetime of the item over multiple years. Examples: Replacing a new fridge or replacing an entire roof.
Property Management: The cost of managing a property.


S.No
Title
Action
1
Title 1
Up
Down
2
Title 2
Up
Down
3
Title 3
Up
Down
4
Title 4
Up
Down
5
Title 5
Up
Down
6
Title 6
Up
Down
7
Title 7
Up
Down