Stata simple key-value pairs
I am defining a categorical variable using a set of named rules. I want to put these rules in the preamble as "parameters" that I can easily change later. I am wondering how to do this. I feel like a reproducible example is not needed here, as I am asking - generally - what is a good way of setting parameters that are essentially key-value structured in Stata?
This is the code I am currently using to classify days in terms of weather event dummies.
preserve
clear
input str12 key str40 val
"Clear" "!(event_thunder|event_snow|event_rain)"
"Rain" "event_rain & !(event_thunder|event_snow)"
"Snow" "event_snow & !(event_thunder|event_rain)"
"Rain & Snow" "(event_snow & event_rain) & !event_thunder"
"Thunder" "event_thunder"
end
scalar N_events = _N
forvalues i = 1/`=N_events'{
scalar event_key`i' = key[`i']
scalar event_val`i' = val[`i']
}
restore
Later in the code, I can iterate over my "key" and "shaft" scalars to define my categorical variable.
gen byte event = 0
forvalues i = 1/`=N_events'{
local event_condition `=event_val`i''
replace event = `i' if `event_condition'
}
I still haven't figured out the correct code to apply the label with my scanners event_key*
. Any advice on this is also appreciated.
source to share
Your code with some tweaks is equivalent to this example:
clear
set more off
sysuse auto
keep make price foreign
preserve
clear
input str12 key str40 val
"for_cheap" "foreign & price < 10000"
"hom_expen" "!foreign & price >= 10000"
end
local numkeys = _N
forvalues i = 1/`numkeys' {
local event_key`i' = key[`i']
local event_val`i' = val[`i']
}
restore
gen byte event = 0
forvalues i = 1/`numkeys' {
replace event = `i' if `event_val`i''
}
save testing, replace
But you just want this, which gives the same result:
clear
set more off
sysuse auto
keep make price foreign
gen byte event = 0
replace event = 1 if foreign & price < 10000
replace event = 2 if !foreign & price >= 10000
// to test these results with previous
cf _all using testing, verbose
You can still put conditions in locals, for example, and use this:
<snip>
local for_cheap foreign & price < 10000
local hom_expen !foreign & price >= 10000
gen byte event = 0
replace event = 1 if `for_cheap'
replace event = 2 if `hom_expen'
Also, you can use loops instead of multiple replace
s:
<snip>
local for_cheap "foreign & price < 10000"
local hom_expen "!foreign & price >= 10000"
local allcond for_cheap hom_expen
local n : word count `allcond'
gen byte event = 0
forvalues i = 1/`n' {
local cond `:word `i' of `allcond'' // extended macro function
replace event = `i' if ``cond''
// syntax for value labels
local lbl `lbl' `i' "`cond'"
}
label define lblevent `lbl'
label values event lblevent
list in 1/25
This puts each named condition in a different local name allcond
. Then use parallel lists to iterate over. I also added code for value labels.
See also help extended_fcn
for reading advanced macro functions (which I used).
If you only want to declare key / values once, you can still do it using only locals:
clear
sysuse auto
keep make price foreign
local allcond for_cheap "foreign & price < 10000" ///
hom_expen "!foreign & price >= 10000"
local n : word count `allcond'
gen byte event = 0
forvalues i = 2(2)`n' {
// get label and condition (extended macro function)
local condlbl `:word `=`i'-1' of `allcond''
local cond `:word `i' of `allcond''
// replace
replace event = `=`i'/2' if `cond'
// syntax for value labels
local lbl `lbl' `=`i'/2' "`condlbl'"
}
label define lblevent `lbl'
label values event lblevent
But for now, your database strategy (and my equivalent code) is easier to read.
By the way, depending on the rest of the code, you can probably avoid it preserve/restore
. You can input
enter the key / values first and then load the working database:
clear
set more off
// input key/val database
input str12 key str40 val
"for_cheap" "foreign & price < 10000"
"hom_expen" "!foreign & price >= 10000"
end
local numkeys = _N
forvalues i = 1/`numkeys' {
local event_key`i' = key[`i']
local event_val`i' = val[`i']
}
// load working database
clear
sysuse auto
keep make price foreign
gen byte event = 0
forvalues i = 1/`numkeys' {
replace event = `i' if `event_val`i''
}
list
source to share