|Stata 7: Making for go through all values of a variable
|Nicholas J. Cox, Durham University, UK
for offers one way of repeating one or more Stata commands. One common pattern is to cycle through all values of a classifying variable. Thus, with the auto data, we could cycle through all the values of foreign or rep78:
. for num 0 1 : whatever if foreign == X . for num 1/5 : whatever if rep78 == X
The question asks for a way to go through all values without specifying them. In practice, this could be useful if you do not know all of the values at the time you type the command; you are writing code to be used with different sets of values; or you know the values but wish to avoid typing a long list.
This FAQ covers three ways of doing it. The first always works, the second usually works, and the third is brute force but is occasionally defensible.
What always works is this three-step process:
. egen group = group(varname)
This maps the distinct values of varname to 1, 2, 3, up to the number of distinct values.
. su group, meanonly
Among other things, this second step leaves behind in r(max) the number of distinct values; see [R] summarize for details on saved results.
Then we use
. for num 1 / `r(max)' : whatever if group == X
Note that the r-class result r(max) is being used immediately after it was produced by summarize. As r-class results are ephemeral and tend not to persist, this is recommended.
That is three lines, but it has two advantages.
. egen group = group(varlist) . su group, meanonly . for num 1 / `r(max)' : whatever if group == XInstead of a single varname, you just need to spell out a varlist in the argument to egen.
In STB-60 there is a command called vallist, which has just one aim in life--to produce a list of the distinct values in a variable. See the on-line help on stb if you wish to know more about the STB (Stata Technical Bulletin) or about installing programs from the STB. If, with the auto data, you type
. vallist rep78
1 2 3 4 5
and leaves behind those values in r(list). So, you can type
. vallist varname . for num `r(list)' : whatever if varname == X
for cycles through all of the values fed to it within r(list). Note again that the r-class result r(list) is being used immediately after it was produced by vallist.
Note also that there are some limitations on this method whenever the values of varname have fractional parts. Suppose it took on values such as 1.1 or 2.1. Then there would be problems with conditions such if varname == 1.1 as described at FAQ: Why can’t I compare two values that I know are equal? or in [U] 16.10 Precision and problems therein. Fortunately, precision is rarely an issue in these circumstances, because whenever people want to do this, it is usually to cycle through categories defined by integer codes.
Suppose you know that some variable takes on most of the integers between 1 and 20, but not necessarily all of them. (It is, say, the number of children in families.) You can make Stata try all of those values and trap cases in which there is no output.
. for num 1/20 : capture noisily whatever if nchildren == X
Here the capture captures any instances in which the command would fail and crash the for. The noisily ensures that we still see output.
This method is crude, but it is a good practical solution whenever it is quicker for Stata to find out for itself which cases will not work than for you to puzzle out more careful code. It could be a very good method if you knew that there were only a few gaps in a sequence.