Stata: Assign labels to range of variables with a loop - loops

Let's say I have 60 variables, none with similar naming patterns. I want to assign labels to all variables, which I stored locally. So for example
local mylabels "dog cat bird"
However I am struggling with the exact expression of the loop. Do I have to store my variable range globally and then use a foreach? Or do I use forvalues?
Edit: I was referring to variable labels. I managed to create a loop, similar to the method used here http://www.stata.com/support/faqs/programming/looping-over-parallel-lists/. However I ran into a more difficult problem: my variables have no particular naming patterns, and the labels have special characters (spaces, commas, %-signs), and here is where my loop does not work.
Some example data (excuse the randomness):
gen Apples_ts_sum = .
gen Pears_avg_1y = .
gen Bananas_max_2y = .
And some example labels:
"Time series of apples, sum, %" "Average of pears, over 1 year"
"Maximum of bananas, over 2 years".
I ran into this entry by Nick Cox: http://www.stata.com/statalist/archive/2012-10/msg00285.html and tried to apply the mentioned parentheses method, like so:
local mylabels `" "Time series of apples, sum, %" "Average of pears, over 1 year" "Maximum of bananas, over 2 years" "'
But could not get it to work.

If you want to label all the variables the same thing, for example "dog cat bird", Then you can use the varlist option for the describe command. Let's say your 60 variables can be generally listed with the expression EXP. Then:
qui des EXP, varlist
foreach variable in `r(varlist)'{
label var `variable' "dog cat bird"
}
Edited:
Taking your example data, I created another local containing the variable names.
local myvar `" "Apples_ts_sum" "Pears_avg_1y" "Bananas_max_2y" "'
local mylabels `" "Time series of apples, sum, %" "Average of pears, over 1 year" "Maximum of bananas, over 2 years" "'
forval n = 1/3{
local a: word `n' of `mylabels'
local b: word `n' of `myvar'
di "variable `b', label `a'"
label var `b' "`a'"
}
Note that I manually created the list of variables. You can automatically create this list using the method I listed above, with des, varlist.
qui des , varlist
foreach var in `r(varlist)'{
local myvar_t "`myvar_t' `var'"
}
You can then use the local myvar_t instead of myvar in the above example.

Related

Matching observations across two string variables

I have two continuous indicators that are measured at the country-level:
GDP per capita
democracy score
I have two string variables that essentially use the same country coding system, such as AFG for Afghanistan. However, I only have 184 observations under the country variable for the GDP data, yet 249 observations under the code variable for the democracy_score data.
I would like to match GDP and democracy score data for observations where the data for both continuous indicators are complete. For instance, the data in the first row below is
"AFG" 2079.9219 "ABW" "0.813"
And I would like to match it with the democracy score data from the third row for observations where the country code is the same, "AFG".
"ALB" 13655.665 "AFG" "0.174"
And the correct data structure would be as follows for AFG:
country gdp_adj democracy_score
"AFG" 2079.9219 "0.174"
Here is a data example:
dataex country gdp_adj code democracy_score
output:
* Example generated by -dataex-. For more info, type help dataex
clear
input str3 country float gdp_adj str3 code str5 democracy_score
"AFG" 2079.9219 "ABW" "0.813"
"AGO" 6602.424 "ADO" "#N/A"
"ALB" 13655.665 "AFG" "0.174"
"ARE" 71782.16 "AIA" "#N/A"
"ARG" 22071.75 "ALB" "0.576"
"ARM" 14317.553 "ANT" "#N/A"
"ATG" 23035.66 "ARE" "0.232"
"AUS" 49379.09 "ARG" "0.632"
"AUT" 55806.44 "ARM" "0.496"
"AZE" 14442.04 "ASM" "#N/A"
"BDI" 729.6584 "ATG" "#N/A"
"BEL" 51977.18 "AUS" "0.861"
"BEN" 3156.439 "AUT" "0.852"
"BFA" 2110.0623 "AZE" "0.200"
"BGD" 5467.208 "BDI" "0.170"
"BGR" 23270.225 "BEL" "0.820"
"BHR" 49768.98 "BEN" "0.473"
"BHS" 35161.832 "BFA" "0.358"
"BIH" 14634.738 "BGD" "0.388"
"BLR" 19279.209 "BGR" "0.602"
"BLZ" 9028.552 "BHR" "0.190"
"BOL" 8528.749 "BHS" "0.688"
"BRA" 14685.128 "BIH" "0.399"
end
You can do it by stacking and reshaping back to wide:
destring democracy_score, replace ignore("#N/A")
stack country gdp_adj code democracy_score , into(country outcome) clear
reshape wide outcome, i(country) j(_stack)
rename (outcome1 outcome2) (gdp_adj democracy_score)
I converted the score from string to double under the assumption that you would want to do some analysis on it. If not, then you can tostring it back.
I also had to tweak the GDP storage to double to avoid some precision issues:
input str3 country double gdp_adj str3 code str5 democracy_score

Latex - labeling tables while using foreach loop

I have a loop in latex, where I access 5 different tables to include in my document. The look has two elements - one variable indicating short name of the category (\n which can be A, O, I, R or H) and the variable that has the long name (\m, which can be "Apartment", "Office", etc).
This loop works as intended for caption and for input. But it does not work for "\label". In other words, the loop produces 5 tables, pulling the right files each time. It puts correct caption on these tables (Apartment, Office, etc), but \label does not get populated correctly. It produces only one label as "output_reg\n" instead of 5 labels as "output_reg_A", "output_reg_O", etc.
I would appreciate all the help I can get!
\documentclass{article}
\usepackage{tikz}
\begin{document}
\foreach \n\m in {A/Apartments,O/Office,R/Retail,I/Industrial,H/Hotel}
{ \begin{table}
\small
\centering
\caption{Regression results \n - \m } \label{output_reg_\n}
\begin{tabular}{ccccc}
a & a & \\
a & a &
\end{tabular}
\end{table}
}
content
% I want to be able to reference the tables as \ref{output_reg_A} and \ref{output_reg_O and so on.
\end{document}

Autohotkey variable expressions for pseudo-arrays - Convert String to Number?

This question was answered at the bottom of this post.
I have looked at 6 different web pages from the AHK forums asking this question, and another one on SO here:
String to Number using autohotkey
...but none of them are working for me. I'm just trying to subtract a number from a string that has been grabbed from the StringSplit function. This is my code:
; Assign entry price variable.
StringSplit, prices, Window1Text, `n
MsgBox, Your entry price is %prices32%.
; Assign Stop Loss variable
SLPrice := %prices32% -= 0.10
MsgBox, Your SLPrice is %SLPrice%.
I receive the error "The following variable name contains an illegal character" on the line "SLPrice := %prices32% -= 0.10", so then I try:
; Assign entry price variable.
StringSplit, prices, Window1Text, `n
MsgBox, Your entry price is %prices32%.
; Assign Stop Loss variable
SLPrice = %prices32% - 0.10
MsgBox, Your SLPrice is %SLPrice%.
...to which I get the output:
Your SLPrice is 7.450 - 0.10
So it just displays the formula as a text string, it doesn't actually do the calculation.
Thoughts? Thanks!
UPDATE
To continue working out this solution, here is my full code up to the part I'm having an issue with, along with screenshots of what's happening:
; Get the latest window text to parse values from it
WinGetText, Window1Text, ahk_class WindowsForms10.Window.8.app.0.f96fc5_r9_ad1
MsgBox, The text is: %Window1Text% ; Displays the window get text values
Sleep, 5
; Assign entry price variable.
StringSplit, prices, Window1Text, `n
MsgBox, Your entry price is %prices32%.
; Assign Stop Loss variable
SLPrice := prices32 - 0.10
MsgBox, Your SLPrice is %SLPrice%.
ANSWER
Thanks to the contributor below, we discovered that there was a "." from the first MsgBox messing up the SLPrice variable, so we updated the SLPrice variable to read:
SLPrice := SubStr(Trim(prices32), 1, 5) - 0.10 ; to pull the left 5 characters
Thanks!
You are on the right track. But, per my comment, note := implies expressions including variable expressions (hence no surrounding %'s):
; Assign entry price variable.
StringSplit, prices, Window1Text, `n
MsgBox, Your entry price is %prices32%.
; Assign Stop Loss variable
; Note, the 32 line also includes non printing characters
; so must be trimmed and then we take the left 5 characters
SLPrice := SubStr(Trim(prices32), 1, 5) - 0.10
MsgBox, Your SLPrice is %SLPrice%.
Should do it . . .
And note, using something := %myvariable% implies reading the contents of a variable named myvariable and using those contents as the variable name. So if myvariable is "test", you are really saying something := test (where something ends up being equal to the contents of the test variable).
Hth,
EDIT per below, here is a working example (BUT PER LATTER COMMENT, SEE BELOW, TOO):
Window1Text =
(
25
26
27
28
)
; Assign entry price variable.
StringSplit, prices, Window1Text, `n
MsgBox, Your entry price is %prices2%. ; using only 2nd line (26)
; Assign Stop Loss variable
SLPrice := prices2 - 0.10 ; again, changed to 2nd line
MsgBox, Your SLPrice is %SLPrice%. ; 25.900000
clipboard := SLPrice
HTH,
FURTHER EDIT: Because this is really cool and illustrates the several concepts as to how they relate to pseudo array variable expressions:
Window1Text =
(
25
26
27
28
)
; Assign entry price variable.
StringSplit, prices, Window1Text, `n ; (prices0 is the number of entries)
InputBox, num,, % "Pick an array number from 1 to " prices0 ; get the array number
; note the variable expression includes the num variable contents
MsgBox, % "Your entry price is " Trim(prices%num%) "." ; depends on array number
; Assign Stop Loss variable
SLPrice := Trim(prices%num%) - 0.10 ; uses the array number value
MsgBox, Your SLPrice is %SLPrice%. ; so depends on the array number
clipboard := SLPrice
Right?
But note, these testers work easily. The real life example from the OP is copied text and the line 32 contains non-printing characters dealt with by Trim(x) and taking only the first few characters from Left with SubStr(x,1,5).

Loop multiple locals

I have the auto dataset and would like to create a few bar graphs:
sysuse auto, clear
local mpg "22 20 17"
local titles "Title1 Title2 Title3"
local path "twentytwo twenty seventeen"
foreach x of local mpg {
foreach y of local titles {
foreach z of local path {
keep if mpg==`x' & foreign==0
egen hv_rank=rank(price)
# delimit ;
graph bar price,
over (make, sort(hv_rank) reverse label(labsize(vsmall)))
ytitle("")
horizontal title("`y'", size(medium))
;
# delimit cr
graph save "$dir_gphs\mpg`z'f0-bal.gph", replace
drop hv_rank
sysuse auto, clear
}
}
}
I do not want to create a bar chart for every possible combination of the "values" of my 3 locals but instead I´d like to have if x=22, then y=Title1 and then z=twentytwo. Likewise if x=20 then y=Title2 and z=twenty.
This must be a simple problem. And I guess my search so far has not brought me any usable results because I do not know the right vocabulary of the problem.
Here is how I would approach the problem.
. local mpg 22 20 17
. local titles `" "Title 1" "Title 2" "Title 3" "'
. local path twentytwo twenty seventeen
.
. forvalues i = 1/3 {
2. local x : word `i' of `mpg'
3. local y : word `i' of `titles'
4. local z : word `i' of `path'
5. display `" `x' --- `y' --- `z' "'
6. }
22 --- Title 1 --- twentytwo
20 --- Title 2 --- twenty
17 --- Title 3 --- seventeen
Or alternatively
. local set1 22 "Title 1" twentytwo
. local set2 20 "Title 2" twenty
. local set3 17 "Title 3" seventeen
. forvalues i = 1/3 {
2. local x : word 1 of `set`i''
3. local y : word 2 of `set`i''
4. local z : word 3 of `set`i''
5. display `" `x' --- `y' --- `z' "'
6. }
22 --- Title 1 --- twentytwo
20 --- Title 2 --- twenty
17 --- Title 3 --- seventeen
As you say, you really want a single loop. Realising that depends on experience rather than finding some documentation.
I can't test this because it hinges on your local directory structure and a global macro that is not defined, so your example is not reproducible. I have made some incidental simplifications.
If your individual elements contained spaces, you would need double quotes to bind.
sysuse auto, clear
forval j = 1/3
local x : word `j' of 22 20 17
local title: word `j' of Title1 Title2 Title3
local path: word `j' of twentytwo twenty seventeen
graph bar price if mpg==`x' & foreign==0 ///
over(make, sort(1) reverse label(labsize(vsmall))) ///
ytitle("") horizontal title("`title'", size(medium))
graph save "$dir_gphs\mpg`path'f0-bal.gph", replace
}

Tabulate multiple variables with common prefix using a local macro

I have a number of variables whose name begins with the prefix indoor. What comes after indoor is not numeric (that would make everything simpler).
I would like a tabulation for each of these variables.
My code is the following:
local indoor indoor*
foreach i of local indoor {
tab `i' group, col freq exact chi2
}
The problem is that indoor in the foreach command resolves to indoor* and not to the list of the indoor questions, as I hoped. For this reason, the tab command is followed by too many variables (it can only handle two) and this results in an error.
The simple fix is to substitute the first command with:
local indoor <full list of indoor questions>
But this is what I would like to avoid, that is to have to find all the names for these variables and then paste them in the code. It seems there is a quicker fix for this but I can't think of any.
The trick is to use ds or unab to create the varlist expansion before asking Stata to loop over values in the foreach loop.
Here's an example of each:
******************! BEGIN EXAMPLE
** THIS FIRST SECTION SIMPLY CREATES SOME FAKE DATA & INDOOR VARS **
clear
set obs 10000
local suffix `c(ALPHA)'
token `"`suffix'"'
while "`1'" != "" {
g indoor`1'`2'`3' = 1+int((5-1+1)*runiform())
lab var indoor`1'`2'`3' "Indoor Values for `1'`2'`3'"
mac shift 1
}
g group = rbinomial(1,.5)
lab var group "GROUP TYPE"
** NOW, YOU SHOULD HAVE A BUNCH OF FAKE INDOOR
**VARS WITH ALPHA, NOT NUMERIC SUFFIXES
desc indoor*
**USE ds TO CREATE YOUR VARLIST FOR THE foreach LOOP:
ds indoor*
di "`r(varlist)'"
local indoorvars `r(varlist)'
local n 0
foreach i of local indoorvars {
**LET'S CLEAN UP YOUR TABLES A BIT WITH SOME HEADERS VIA display
local ++n
di in red "--------------------------------------------"
di in red "Table `n': `:var l `i'' by `:var l group'"
di in red "--------------------------------------------"
**YOUR tab TABLES
tab `i' group, col freq chi2 exact nolog nokey
}
******************! END EXAMPLE
OR using unab instead:
******************! BEGIN EXAMPLE
unab indoorvars: indoor*
di "`indoorvars'"
local n 0
foreach i of local indoorvars {
local ++n
di in red "--------------------------------------------"
di in red "Table `n': `:var l `i'' by `:var l group'"
di in red "--------------------------------------------"
tab `i' group, col freq chi2 nokey //I turned off exact to speed things up
}
******************! END EXAMPLE
The advantages of ds come into play if you want to select your indoor vars using a tricky selection rule, like selecting indoor vars based on information in the variable label or some other characteristic.
You could do this with
foreach i of var `indoor' {
tab `i' group, col freq exact chi2
}
This would work. It is almost identical to the code in the question.
unab indoor : indoor*
foreach i of local indoor {
tab `i' group, col freq exact chi2
}
foreach v of varlist indoo* {
do sth with `v'
}

Resources