3 Programar do - files
3.1 Programar en Stata
Esta sección esta basada en: An introduction to Stata Programing (), en notas de clase de la profesora Erin Hengel, en Advanced Stata Topics del profesor Alexander C. Lembcke, en Seventy-six Stata tips , en Top 10 ``gotchas” de y en Data Management Using Stata. A Practical Handbook de .
3.1.0.1 ¿Qué es programar en Stata?
Programar en Stata es:
- Escribir
do - files: una secuencia de comandos ejecutables a través de un archivo.do. - Escribir los que formalmente en Stata es un programa: un conjunto de comandos que incluyen el comando
program. Un programa en Stata se guarda como un ado - file. - Escribir lenguaje de programación matricial: denominado mata.
3.1.0.2 do - files
El uso de do-file garantiza la replicabilidad del análisis de datos utilizando Stata. Recordar que un do-file puede llamar a otros (ej. master do.file. La jerarquización de los do-file puede ser importante para proyectos grandes o complejos. Es importante evitar trabajar en Stata interactivamente. Únicamente hay que hacerlo para inspeccionar datos (recordar practicas Sección 3.1).
3.1.0.3 ado - files
Sirven para crear tus propios en Stata. Una vez que armes tu programa y lo guardes en la carpeta de ado-file puedes utilizarlo como cualquier otro comando de Stata. Por ejemplo, puedes agregar las opciones if, in range y otras. También puedes escribir un documento de ayuda (help} que explique el programa. Crear tus propios comandos es una muy buena forma de ser más eficiente al trabajar con Stata (recordar Sección 1).
Mata para ado-files: Los ado-files pueden realizar tareas más complejas que involucren ejecutar el comando múltiples veces.
- El lenguaje de programación mata es mucho más rápido que un
ado-file. - Útil para realizar tareas que sean intensivas computacionalmente.
- No es solo un lenguajes de programación que utiliza matrices. También sirve para tareas que involucran texto o listas.
- Próximante discutiremos este lenguaje.
3.1.1 Comandos y funciones claves (y algunos detalles)}
Revisaremos algunos aspectos necesarios para mejorar la eficiencia al trabajar en Stata.
- Directorios y uso de
profile.do. - Tipos de comandos.
- Tipos de datos y uso de
compress. - Uso de
capture,preserveyrestore.
3.1.1.1 Directorios
cdypwdsirven para fijar y conocer mis directorios. Es importante utilizar dobles comillas en los casos en que la ruta del directorio tenga espacios.- El comando
sysdirprovee una lista de los directorios importantes para Stata. - El comando
updatesirve para actualizar los comandos. - La carpeta
PLUSes el directorio donde se guardan comandos descargados. Si utilizasssc, se guardara en esta carpeta.
PERSONALpara tus propiosado-files.
3.1.1.2 Profile do
¿Qué es profile do?
- Una opción no tan conocida es la utilización de
profile.do - Este archivo se ejecuta cada vez que Stata se inicia. Si no tienes uno guardado no pasa nada.
- Este
do-filepermite, por ejemplo, fijar tu directorio de trabajo inicial, cambiar características de los gráficos, generar atajos.
- También se puede hacer que Stata abra un log-file y lo guarde siempre en el mismo lugar.
- Cada vez que inicies sesión Stata ira por
profile.do. Si lo encuentra lo va a ejecutar.
- Stata recomienda guardar
profile.doen home directory (ver help profilew para ususarios de windows y profilem para Mac). - Vamos a ver como modificar
profile.do. En particular:- Ajustes generales.
- Establecer las características de los gráficos.
- Establecer atajos
- Abrir, cerrar y guardar un log-file con la fecha.
Ejercicio 3.3.1:
Instrucciones
- Descargar carpeta ejercicios-clase3.
- Abrir
profile.doe inspeccionar cada una de las lineas del código.
Preguntas
- Agrega dos elementos a alguna sección.
- Modifica las carpetas según las características de tu computadora.
- Guarda
profile.doen el home directory. Ejecutar nuevamente Stata y verificar que el código se ha ejecutado.
3.1.1.3 Tipos de comandos
Comandos r-class y e-class
- Muchos comandos en Stata (ej.
summarize,correlate,regress) hacen que sea posible utilizar sus resultados una vez que estos son ejecutados. summarizeycorrelateson comandosr-class. Es decir, comandos que guardan sus resultados enr().regresses un comandoe-class. Es decir, comandos que guardan sus resultados ene().return listretorna los valores guardados enr()
* r-class
sysuse auto.dta, clear
summarize mpg
return list
summarize mpg, detail
return list
display "La asimetría de mpg es" r(skewness)
summarize price, detail
return list Su limitación es que solo están disponibles los valores del último comando r-class ejecutado.
Los comandos e-class son comandos de estimación. Para verlos ereturn list y para llamarlos individualmente e(nombre). Guardan más información que los de r-class : matrices, vectores y funciones. La información de los comandos e-class sigue estando disponible una vez que utilizamos algún comando r-class`. Aquí una diferencia!
Un ejemplo clásico son las estimaciones de regresión lineal.
regress mpg weight length rep78
display "La regresión se estimo para " e(N) " observaciones."
ereturn listEn general cualquier comando de estimación se guarda en esta clase de formato.
3.1.1.4 Tipos de datos
numeric y string
- La mayor distinción entre tipos de datos es entre numeric y string.
- Al trabajar con datos muchas veces es necesario realizar conversiones entre estos dos formatos. Los comandos
destring,tostringyencodeson útiles para estas tareas (si alguien tiene dudas con alguno me escriben). - strings pueden soportar un máximo de 244 caracteres con un
bytepor cada carácter. - Por ejemplo, una variable del tipo
str20requiere 20bytespor observación.
Clasificación de los datos
- Para las variables en formato numeric los tipos de datos son:
byte,int,long,floatydouble. - Los tres primeros solo puede almacenar valores enteros.
longpuede almacenar todos los números de 9 dígitos, pero es limitado para 10 dígitos. floatydoublepueden almacenar números grandes.- No asumir que
floatserá aritméticamente exacto. Por ejemplo:
display float(16777216)
16777216
display float(16777217)
16777216¿Como utilizar esto para programar efectivamente en Stata?
- IDs con muchos dígitos (y caracteres) guardarlos como string. No como
integers,floatodoubles. - No confiar en test exactos contra una constante con datos en formato
float. Utilizar formatodoublepara cualquier serie que necesita ser precisa (ej. suma de los residuos de una regresión). - Utiliza
integerscuando sea apropiado (ej. variables dicotómicas). Guardar valores comointobyteayuda a utilizar de forma más eficiente el espacio en el disco. compressexamina cada variable y determina si estas pueden ser guardadas de forma más eficiente. Utilizarlo.
Si se especifican valores iniciales fuera de los rangos permitidos para cada tipo de dato el resultado será un missing.
clear all
set obs 10
generate byte var1 = 101
summarize var1 Notar que no se genera ninguna alerta de missing cuando este se crea. Esto es distinto para variables que ya existen.
clear all
set obs 10
generate byte var1 = 1
replace var1 = 101Si el valor esta fuera de los rangos permitidos, la variable se guarda en un formato mayor. byte a int, int a long, a float a double. En este caso un mensaje aparece.
3.1.1.5 capture, preserve y restore
Manejando errores: capture
- Sirve para evitar que Stata aborte cuando detecta un error.
- Bueno para cuando quieres borrar algo que ya no se encuentra. Lo malo es que suprime todos los errores y oculta todo lo que puede ir mal.
set obs 10
generate byte var1 = 5
generate byte var2 = 10
capture drop var1 var2 var3
describe var1 var2Código crea var1 y var2, luego las elimina incluyendo una variable que no existe. Al contrario de lo que se intuye, no se borran las variables, dado que hay una variable que no existe. La recomendación es siempre utilizar capture con moderación. Puede ser utilizado en bloque para así no tener que utilizarlo en cada linea.
sysuse auto.dta, clear
capture{
reg price mpg-trunk
reg price mpg-weight
reg price mpg-foreign
}
ereturn list preserve y restore
- Algunos comandos en Stata remplazan la base actual por una nueva (ej.
collapseocontract). - Utilizar
preserveyrestorees útil en estos casos. - En caso de que queramos obtener estadística descriptiva agregada y asociarla a observaciones podemos utilizar estos comandos.
* Ejemplo con collapse
sysuse auto.dta, clear
generate lprice = log(price)
preserve
collapse (max) max_lprice=lprice max_mpg=mpg ///
(iqr) iqr_lprince = lprice iqr_mpg = mpg if !missing(rep78), by(rep78)
sort rep78
tempfile repstats
save `repstats'
restore
sort rep78
merge m:1 rep78 using `repstats'
assert _merge != 2
summarize lprice max_lprice max_mpg
* Ejemplo con contract
sysuse auto.dta, clear
preserve
contract mpg, cfreq(cumfreq) percent(percentage) cpercent(cumpercent)
sort mpg
tempfile mpgfreq
save `mpgfreq'
restore
sort mpg
merge m:1 mpg using `mpgfreq'
assert _merge != 2
summarize _freq cumfreq percentage cumpercent3.1.1.6 Missing values
- En general uno utiliza
if variable !=.para evitar incluir missings. - Mejor practica es
variable <.para excluir todos los valores en missing. Otra opción esif !missing(variable). - Los missing están codificados internamente como valores mayores a cualquier número. El menor valor de todos los missing es el punto. Al utilizar
if variable <.es como decir, solo utiliza los números. - Como vimos en la Sección 3.1 hay muchos problemas al no tratar bien los missings. Este problema se incrementa al momento de trabajar con bases de datos imposibles de inspeccionar. Veremos algunas recomendaciones que pueden ser utiles para evitar estos errores.
Los comandos tratan distinto a los missings
- Cualquier función de datos missing será missing.
- Cuando se calcula un promedio o una desviación estándar solo valores no missing son considerados (ej.
sum).
- Algunos comandos en Stata manejan los missing de otras formas. Por ejemplo, las funciones
max,miny las funciones para filas deegen:rowmax(),rowmean(),rowmin(),rowsd()yrowtotal()ignoran los missing. Por ejemplo,rowmean(x1,x2,x3)calcula el promedio de las variables y solo retornara missing si todas lo son. - Por ejemplo,
rowmean(x1,x2,x3)calcula el promedio de las variables y solo retornara missing si todas lo son. collapse (sum)trata a los missing como ceros.
Calcular un promedio con missings
clear
set obs 10
gen var1 = rnormal()
gen var2 = 5
gen var3 = .
gen promedio = (var1 + var2 + var3)/3
egen promedio1 = rowmean(var1 var2 var3)PromedioSinMissing da como resultado missings. PromedioConMissing no considera missings. Es importante tratar de entender como funcionan los missings de los comandos que utilizas.
Generar variables considerando missings: Al crear una variable dicotómica, gen y gen byte tratan a los missing de formas distintas.
local N = 500
set obs `N'
gen indicador = uniform() < .5
replace indicador =. if mod(_n, 2) == 0
* Si indicador es missing, variable sera missing
gen variable_primercaso = 1 if indicador == 1
replace variable_primercaso = 0 if indicador == 0
* Si indicador es missing, variable sera cero.
gen variable_segundocaso=(indicador==1)
\end{minted}
\end{itemize}sum() considera missing como ceros.
clear all
set obs 4
generate byte var1 = cond(mod(_n,2)==1, 1, .)
generate byte var1sum = sum(var1)
list, noobsmax() trata a los missing como si no estuviesen allí.
display max(-5,.)tabmiss, mvdecode y mvencode
- En ocasiones los missing difieren en notación (ej. al importar datos de otro paquete). Siempre que trabajes con una base de datos nueva es importante recodificar. Notar que no todos tienen que ir a un punto. Todo depende del origen de los missing.
mvdecodeymvencodepueden ser útiles en este tipo de casos.mvdecodepermite recodificar valores numéricos como missing. Útil cuando valores son representados como -99, -999.mvencodehace lo inverso. Mapea missing como numéricos.- El comando
tabmissinspecciona todas las variables de una base de datos y reporta losmissingtotales y como fracción del total de observaciones.
clear all
set seed 1234
local N = 50
set obs `N'
gen income = abs(int(rnormal(0,5)))
assert income >= 0
replace income =. if mod(_n, 2) == 0
* Para ver los missing en variables
tabmiss
* Transformar un valor númerico a missing
mvdecode income, mv(2)
* Transformar varios valores númericos a missing.
mvdecode income, mv(2 5)
* Transformar varios a missing, pero identific ́andolos.
mvdecode income, mv(3 = .a \ 6 = .b)
* Missings se cambian de vuelta a su valor original.
mvencode income, mv(.a = 3 \ .b = 6)Ejercicio 3.3.2:
Instrucciones
Abrir ejercicios-clase3.do y ejecute las líneas correspondientes al ejercicio 2.
Pregunta
Compare las opciones 1, 2 y 3 en relación a como tratan los missing. Explique las diferencias entre cada una de estas opciones.
generate, replace y missing: Sólo unas pequeños detalles.
clear
cd "$ejercicio3"
use census2c, clear
* Opción 1
gen smallpop_o1 = 1 if pop<=5000
replace smallpop_o1 = 0 if pop>5000
* Opción 2
gen smallpop_o2 = (pop <= 5000)
* Opcion 3
gen smallpop_o3 = (pop <= 5000) if !missing(pop)Opción 1 es la típica. Ojo no esta considerando missing. Es necesario agregar & !missing(pop). Escrito de esta forma, si pop es missing, smallpop será cero. Opción 2 es más simple, pero si cualquier valor de pop es missing será evaluado como un cero también. La razón es que los missing en Stata son considerados como números muy grandes para el programa. La Opción 3 soluciona el problema.
3.1.1.7 String a numeric y al revés
De string a numeric
- Si las variables han sido mal clasificadas como string puedes utilizar la función
real(). - Por ejemplo:
generate idpaciente = real(pacienteid). - El comando anterior genera missing para todas las observaciones que no puedan ser interpretadas como numéricas.
- Mucho mejor es utilizar
destring, replace. - Otro caso usual es que tenemos datos en formato
stringy queremos que tengan un equivalente. El comandoencode. No es aconsejable utilizar este comando para valores numéricos guardados como string.
De numeric a string
- Hay veces en las que se quiere generar un equivalente string a valores numéricos.
- Tres comandos:
string(),tostring()ydecode(). - Un ejemplo es querer mantener los 0 que estan al inicio de un código ID.
- El comando
tostring zip, format(\%05.0f) generate(idstring)genera un string de cinco digitos con los ceros al inicio. decode()sirve para un caso en que tengas un id en numérico, pero que no la tengas en string.
Strings entre comillas: importa poner las comillas bien.
display "Este es un string normal"
display "Este no es un string con "comillas" "
display `"Este si es un string con "comillas""'3.1.1.8 Funciones para generar variables
generate y replace: función cond()
- Si quiero que un resultado sea “a” si una condición es verdadera y “b” si es falsa.
- La función
cond(x,a,b)posee esta capacidad sin la necesidad de utilizarif.
* Útil para construir una tabla
generate netmarr2x = cond(marr/divr > 2, 1, 2)
label define netmarr2xc 1 "marr > 2 divr" 2 "marr <= 2 divr"
label values netmarr2x netmarr2xc
tabstat pop medage, by(netmarr2x) Las observaciones en Stata estás numeradas desde el 1. _N es el mayor número de observaciones, mientras que el actual es _n. sort (ascendete) y gsort (ascendete o descendente) alteran el orden de las observaciones. Como recomendación eviten generar variables o condiciones que dependan de la posición especifica de una observación.
* Ejemplo 1: uso de gsort
gsort region -pop
by region: generate totpop = sum(pop)
* Ejemplo 2: uso de _n y _N
by region: list region totpop if _n == _N
* Ejemplo 3: sort
generate largepop = 0
replace largepop = 1 if pop > 5000 & !missing(pop)
gen smallpop = (pop <= 5000) if !missing(pop)
generate popsize = smallpop + 2*largepop
label variable popsize "Population size code"
label define popsize 1 "<= 5 million" 2 "> 5 million", modify
label values popsize popsize
bysort region popsize: egen meanpop2 = mean(pop) recode para variables discretas: recode crea una nueva variable basada en otra variable.
* Esta no es una buena opción
replace newcode = 5 if oldcode == 2
replace newcode = 8 if oldcode == 3
replace newcode = 12 if inlist(oldcode, 5, 6, 7)
* Esta si es una buena opción
recode oldcode (2 = 5) (3 = 8) (5/7 = 12), gen(newcode) El signo (\(=\)) es para indicar valor antiguo a valor nuevo. No es necesario aplicarlo linea por linea. recode produce un código más eficiente.
recode para variables continuas: recode(x,x1,x2,x3,x4,xn) para variables continuas de forma tal de generar intervalos tal que \(x \leq x_1 ; x_1 \leq x \leq x_2\) y así sucesivamente. Los resultados son iguales a los límites creados.
use census2c, clear
generate breaks = recode(medage, 29, 30, 31, 32, 33)Otros comandos que cumplen una función parecida son floor y ceil(). Ambos sirven para generar un valor entero. El primero para redondear hacia abajo y el otro hacia arriba. floor(x) retorna el entero \(n\) tal que \(n \leq x < n + 1\) mientras que ceil(x) es tal que \(n - 1 < x \leq n\).
use census2c, clear
generate popurbfloor = floor(popurb)
generate popurbceil = ceil(popurb)irecode para variables continuas: irecode(x,x1,x2,x3,x4,x_n) es una alternativa para categorizar grupos también. Por ejemplo:
generate size = irecode(pop, 1000, 4000, 8000, 20000)
label define popsize 0 "<1m" 1 "1-4m" 2 "4-8m" 3 ">8m"
label values size popsize
tabstat pop, stat(mean min max) by(size)Categorizara cada grupo según el intervalo en el que este. Parte del cero!. $x x_1 $, \(x_1 \leq x \leq x_2 \rightarrow 1\) y así sucesivamente.
Crear cuartiles con xtile: Con xtile podemos querer clasificar las variables según cuantiles (quintiles, deciles, cuartiles, etc).
* Creamos cuartiles para población
xtile popcuart = pop , nq(4)
tabstat pop, stat(n mean min max) by(popcuart)Ejercicio 3.3.3:
Instrucciones
- Cargar la base
auto.dta
Pregunta
- Genere una variable que sirva para redondear hacia abajo la variable
mpgen en múltiplos de 5, de modo que cualquier valor de 10 a 14 se redondee a 10, cualquier valor de 15 a 19 a 15 y así sucesivamente.
3.1.1.9 Funciones de egen
Todos y todas conocemos algunas de las típicas funciones de egen.
clear
* Ejemplo del uso de egen
generate size = irecode(pop, 1000, 4000, 8000, 20000)
label define popsize 0 "<1m" 1 "1-4m" 2 "4-8m" 3 ">8m"
label values size popsize
bysort size: egen avgpop = mean(pop)
generate popratio = 100 * pop / avgpop
format popratio \%7.2f
list state pop avgpop popratio if size == 0 Otras funciones son iqr(), kurt(),mad(), mdev(), median(), mode(), pc(), pctile(), rank(), sd(), skwe(), std().
egenmore
- Menos conocida es la colección de funciones adicionales de
egenhechas por Nicholas J. Cox. - Estas funciones están contenidas en el comando
egenmore. bom()yeom()crean variables de fechas que corresponde al primer y último día de un mes determinado.corr()calcula correlaciones y covarianzas mientras quevar()calcular la varianza.semean()calcula la desviación estándar del error de una media.record()permite calcular el valor más alto o más bajo de una serie.
* Ejemplo 1: Generar variable que tenga la primera palabra de una frase (wordof)
egen firstword = wordof(make), word(1)
list firstword make in 1/15
* Ejemplo 2: Para generar automáticamente valores extremos (outside, 1,5 RIQ)
egen extrmpg = outside(mpg)
tab extrmpg, missingrall() y rany() son útiles para el análisis de datos. Evaluan una condición y genera un indicador si todas o alguna observación la cumple.
set obs 12
gen a = 1 in 1
gen b = 2 in 2/4
gen c = -3 in 5/7
gen d = 4 in 8/10
gen e = . in 11/12
egen any = rany(a b c d e) , c(@ > 0 & !missing(@))
egen all = rall(a b c d e) , c(@ > 0 & !missing(@)) 3.1.2 Macros locales y globales
3.1.2.1 Nombrar macros
- Una macro es un contenedor que puede almacenar números o nombres de variables.
- Puede ser
localoglobal. La primera es temporal, la segunda no.
- Un ejemplo de variable local es:
local NivelEstres Nada Medio Moderado Severo
display "Los niveles de estrés son: `NivelEstres'"El primer comando define la macro y sus valores. Para llamar a la macro hay que utilizar las comillas (“). local nombre texto \(\rightarrow\) local nombre = text \(\rightarrow\) local nombre = "text".
Ojo con las rutas:
- En ocasiones voy a querer utilizar una macro dentro de la ruta de una carpeta.
- Es importante utilizar siempre
/o bien\\. De otra forma no lo reconocerá.
local filename base.dta
use "H:\ECStata\`filename'"
r(601);
* Para corregir el error, dos caminos:
use "H:\ECStata\\`filename'"
use "H:/ECStata/`filename'"Ejercicio 3.3.4: Compare los siguientes comandos y comente las diferencias:
display "Dos mas dos = 2 + 2"display "Dos mas dos= 2 + 2’“`
Ojo con el signo igual: Algunas veces es bueno colocar un signo \(=\) al definir macros. Por ejemplo, cuando redefinimos variables.
local contador 0
local NivelEstres Nada Medio Moderado Severo
foreach a of local NivelEstres {
local contador = `contador' + 1
display "Nivel de Estres `contador' : `a'"
}La primera parte sirve para definir la macro mientras que la segunda sirve para dar cuenta de su valor actual. Al actualizar, ocupen igual.
Sin signo igual: En algunas ocasiones queremos escribir una macro dentro de un loop. En estos casos es conveniente evitar el signo igual.
local contador 0
local NivelEstres Nada Medio Moderado Severo
foreach a of local NivelEstres {
local contador = `contador' + 1
local nuevalista `nuevalista' `contador' 'a'
}
display "`nuevalista'" El local nuevalista define una macro como string que posee su propio contenido, el valor de contar y el valor del iterador.
3.1.2.2 Generar variables, contadores y condiciones con macros
Podemos utilizar macros para renombrar variables.
clear
forvalues a = 10/20{
gen v`a' = rnormal()
}
* Renombramos variables
forvalues i = 11/15 {
rename v`i' x`=1960 + `i''
}En este fragmento de código, Stata evalúa la expresión 1960 + 'i' antes de evaluar la macro externa. Por ejemplo, cuando pase por el iterador i = 11, el nuevo nombre de la variable será x1971.
Resumir condiciones: Podemos utilizar macros para resumir condiciones. Esto es útil para estimar modelos o generar estadística descriptiva.
clear
sysuse auto
local cond "if foreign==0"
local varlist "mpg rep78 trunk weight turn"
* Estimar la regresión considerando la condicíòn
reg price `varlist' `cond'Agrupar en base a una condición: Imaginemos que ahora queremos estimar una regresión para todas las compañías de auto que empiezan empiezan con B.
local autoname B
reg price mpg weight if substr(make,1,1)=="`autoname'"La mejor manera de pensar en esto es hacer lo que hace Stata: reemplazar "ctyname" por su contenido substr(país,1,1)=="ctyname’“. Al hacerlo, se convierte ensubstr(país,1,1)==”B”. Si se omiten las comillas dobles, se obtienesubstr(country,1,1)==B`, lo que da lugar a un error.
Contadores: Las macros también pueden ser útiles para contadores.
* Para adelante
local i = 1
local ++i
di `i'
* Para atrás
local i = 1
local --i
di `i' Muy útil para hacer gráficos o guardar datos en matrices.
Utilizar una macro para estimar regresiones: Imaginen que desean estimar regresiones sobre un conjunto de variables donde una parte de este conjunto esta fija y la otra parte es variable.
local rhs mpg weight
reg price `rhs' if foreign == 0
local rhs "`rhs' headroom trunk"
reg price `rhs' if foreign == 0 ¿Qué ocurre si queremos hacerlo por separado? ¿Uno a uno?
local rhs "mpg weight \`add_var'"
local add_var "headroom"
reg price `rhs' if foreign == 0
local add_var "trunk"
reg price `rhs' if foreign == 0
local add_var "turn"
reg price `rhs' if foreign == 0 Lo que ocurre cuando hacemos referencia a una macro es que su valor se introduce en ese punto. El uso de una barra invertida en su lugar hace que se introduzca la referencia de la macro, es decir, no se sustituirá el valor de add_var sino el término `add_var'. Así que cada vez que llamamos a la local rhs el valor actual de el local add_var es sustituido.
Ejercicio 3.3.5:
Instrucciones
- Cargar la base
auto.dta
Preguntas
Defina una variable macro llamada
controlque contengampg,rep78yheadroom. Estime una regresión entrepriceycontrolpara vehículos extranjeros y de nuevo para vehículos domésticos.Ejecute
summarize mpgjunto conreturn list. Defina dos macrosdisplaylocal mean1 r(mean)ylocal mean2 = r(mean). ¿Son iguales?
3.1.2.3 Globales
Crear macros globales
- Se crean con el comando
global. - Útiles para fijar directorios o programas.
- En otros casos es mejor utilizar
local.
* Para generarla
global variable
* En caso de querer llamarla
display $variable3.1.2.4 Funciones extendidas de macros
¿Qué son las funciones de macros extendidas?
- Stata también define ciertas macro. Estas se denominan extended macro functions o macros extendidas.
- En algunos casos contienen información sobre tu sistema operativo, sobre la última estimación que se realizo o sobre la base de datos.
- El
help extended_fcny la documentación que la acompaña proporcionan una descripción completa de la sintaxis de cada función de macro extendida (hay muchas). Muchas tienen ligeras variaciones de sintaxis entre ellas (por ejemplo, algunas requieren que las macros estén entre comillas dobles; otras no lo permiten).
* La sintaxis general es:
local nombremacro: función macro extendidaMirar labels
* Para mirar los labels de trunk
sysuse auto, clear
local tlab : variable label trunk
display "`tlab'"variable label recupera el nombre asignado a una variable.
Contar dentro de un local
* Para contar dentro de un local
local NivelEstres Nada Medio Moderado Severo
local wds: word count `NivelEstres'
display "Hay `wds' niveles de estres:"
forvalues i = 1/`wds' {
local wd: word `i' of `NivelEstres'
display "Nivel `i' is `wd'"
}word count y word como funciones de extensión que operan sobre strings.
Conocer tipos de datos
* Para conocer tipos de datos
sysuse auto, clear
local stortype : type make
display "`stortype'"Ojos con las comillas dobles (nuevamente): Algunas veces las macros contienen comillas dobles. Para poder escribirlos sin errores es necesario modificar levemente la forma en que se llama a la variable local
* Con error
local answers yes no "do not know"
display "`answers'"
* Sin error
local answers yes no "do not know"
display `"`answers'"'Ejercicio 3.3.6:
Preguntas
- Use una macro extendida para mostrar el tipo de dato (ej.
int,float,long,…) dempg. Revise elhelpdeextended_fcn. - Use una macro extendida para retornar el valor del label asociado a
foreigncuando es igual a 1. - Use una macro extendida para mostrar solo la primera variable de `
controls'. - Utilice una función extendida de macros para mostrar todos los archivos de su directorio actual (sugerencia: utilice comillas compuestas cuando muestre los nombres de los archivos).
3.1.2.5 Funciones de macro extendidas para listas
Stata también define ciertas macro para operar sobre listas. Estas funciones permiten combinar listas, buscar elementos dentro de una lista o bien buscar elementos comunes entre dos listas. Conveniente revisar help macrolist para más funciones.
* Sintaxis:
local nombre macro: list función
* Ejemplo de lista
local animales "gato perro gato loro loro"
local uniqanimales : list uniq animales
display "`uniqanimales'"Función levelsof: El comando levelsof lista los valores distintos de una variable. Al agregar la opción local(nombremacro) esto se guardara como una macro.
* Sintaxis básica
sysuse auto, clear
levelsof rep78
display "`r(levels)'"
* Sintaxis cuando hay variables categóricas.
levelsof foreign, local(levels)
foreach l of local levels {
di "-> foreign = `: label (foreign) `l''"
reg price mpg if foreign == `l'
}3.1.2.6 Manipulación de locales vía listas de macros
Listas de macros: Las macro lists permiten obtener el número de elementos de una macro, trabajar con valores duplicados, ordenar elementos. Veremos cuatro aplicaciones:
- Elementos duplicados.
- Agregar y remover elementos.
- Uniones e intersecciones.
- Ordenar elementos.
Elementos duplicados: dups extrae todos los elementos sobrantes.
* Deja solo los unicos
local fib 0 1 1 2 3
local fib_nodups : list uniq fib
display "`fib_nodups'"
* Quita todo los duplicados
local fib 0 1 1 2 3
local fib_dups : list dups fib
display "`fib_dups'"Agregar y remover elementos: Es básicamente pegar elementos de una macro con otra. Definamos dos variables locales: vars y coef y peguémoslos.
local vars x y z
local coefs a b c
local vars_coefs `vars' `coefs'
display "`vars_coefs'"Para remover tenemos que definir un nuevo local con los elementos que queremos quitar y sustraerlo del original. Supongamos que queremos actualizar el contenido de vars eliminado “y”.
local not y
local vars : list vars - not
display "`vars'"Unión de elementos: Podemos pegar todos los elementos diferentes entre dos listas.
local A house tree car
local B computer car bike
local all_things : list A | B
display "`all_things'"Noten que los elementos de car no fueron pegados. Notar que esto es distinto a simplemente pegar macros entre sí.
Intersección de elementos: Podemos hacer la intersección entre dos elementos de una lista. Esto corresponde a los elementos que pertenecen a ambas macros.
local A house tree car
local B computer car bike
local common_things : list A & B
display "`common_things'"Noten que en este caso solo car se mantiene.
Ordenar elementos: En ocasiones queremos ordenar los elementos de una lista contenida en una macro.
local names camila camilo pedro paula
local names : list sort names
display "`names'"Para hacer que los elementos de una macro se ordenen aleatoriamente es conveniente utilizar mata
local nums 1 2 3 4 5
mata : st_local("random_nums", ///
invtokens(jumble(tokens(st_local("nums"))')'))
display "`random_nums'"3.1.2.7 creturn
Macros con creturn
- En algunos casos al utilizar
localoglobalvamos a querer fijar algunos parámetros. - Para este propósito utilizar
creturn. Algunos ejemplos son:c(current_date),c(pwd),c(current_time),c(stata_version),c(pi),c(alpha),c(Wdays).
Ejercicio 3.3.7:
Preguntas
- Define una macro llamada comestibles con peras, manzanas, fresas, yogur, vino y queso en ella. Ponla en orden alfabético.
- Define una macro llamada unión que contenga los miembros de la macro animales y comestibles y luego utiliza una función de lista extendida de la macro para mostrar el número de palabras que contiene.
- Ordena unión y muestra la posición de la palabra “vino” utilizando una función de lista extendida de macros.
3.1.3 Estructuras de datos
3.1.3.1 Escalares
- Los escalares pueden contener valores numéricos o strings. Un escalar solo puede contener un valor.
- La sintaxis para generar un escalar es
scalar scalar_name = exp.
quietly: summarize mpg
scalar mean_mpg = r(mean)
quietly: summarize rep78
scalar mean_rep78 = r(mean)
display "r(mean) guarda el promedio de rep78: " r(mean)
display "Pero tambien podemos recuperarlo:" mean_mpgPara utilizar un escalar en una operación solo es necesario llamarlo por su nombre. Para listar el contenido de todos los escalares scalar list. Para borrar scalar drop scalar_name o si quiero eliminar todo scalar drop _all. Los escalares permiten parametrizar un do-file.
use fem2, clear
scalar lb1 = 80
scalar ub1 = 88
scalar lb2 = 89
scalar ub2 = 97
forvalues i = 1/2 {
display _n "IQ" "lb`i'" "-" "ub`i'"
tabulate anxiety if inrange(iq, lb`i', ub`i')
}3.1.3.2 Elementos y operaciones con matrices
Stata puede generar matrices.
reg weight age age2
matrix b = e(b)
matrix list b
matrix V = e(V)
matrix list VLas matrices son muy importantes para guardar resultados y exportarlos de forma conveniente. También son útiles para cuando se quieren hacer estimaciones de muchos parámetros y para distintos conjuntos de datos.
Operaciones con matrices: Se puede operar con matrices. Por ejemplo, sabemos que \(b = (X'X)^{-1}X'y\) y que \(V = \sigma^{2}(X'X)^{-1}\). Si queremos extraer solo la matriz \(X'y\) tenemos que operar, calculando \(\frac{1}{\sigma^{2}}V^{-1}b\).
matrix define b = e(b)'
matrix define xty = inv(V) * b /e(rmse)^2
matrix list xty e(b)’ indica la traspuesta, mientras que inv() es para calcular la matriz inversa.
Llamar a los elementos de una matriz: Se puede acceder a los escalares contenidos en las matrices. Por ejemplo, si queremos obtener los elementos de la matriz \(e(b)\) tenemos:
display "The coefficient on weight is: " _b[weight]
display "Its standard error is: " _se[weight]
* Valores predichos
generate anxietyhat = _b[_cons] + _b[weight] * weight + ///
_b[age] * age + _b[age2] * age2También podemos utilizar las posiciones de los elementos de la matriz (b[i,k)]).
3.1.3.3 Funciones
Solo disponibles para comandos e-class. Por ejemplo, si estimamos una regresión veremos que la unica función disponible es e(sample).
sysuse auto
regress mpg weight length rep78
ereturn liste(sample) nos indica si una determinada observación se utilizó para estimar la regresión. Es decir, es igual a uno si una observación estaba en la muestra de estimación y 0 si fue excluida.
Ejercicio 3.4.1:
Preguntas:
- Estime una regresión de mpg contra weight length rep78 utilizando base de datos auto, pero solo para los autos extranjeros (
foreign == 1). - Genere una nueva variable, llamada
enmuestraque tome los valores dados por la funcióne(sample). - Utilizando
br, observe los valores deenmuestra. ¿Qué observa? - Calcule la estadística de
mpgsolo para las observaciones que fueron incluidas en la regresión.
3.1.4 Iteradores
3.1.4.1 Foreach
foreach y forvalues: forvalues itera sobre una lista de números y foreach recorre los elementos de una macro, o los nombres de las variables de una lista de variables, o los elementos de una lista de números.
* Foreach
foreach animal in cats and dogs {
display "`animal'"
}
* Forvalues
forvalues i = 1(1)100 {
generate x`i' = runiform()
}Hay algunas variaciones en foreach según el tipo de lista. La sintaxis es similar a la recien presentada, pero difiere en dos aspectos:
inse remplaza porof.- Hay que llamar al identificador.
- Veamos como iterar sobre una lista de globales y locales. \end{itemize}
* Sobre locales y globales
local money "Franc Dollar Lira Pound"
foreach currency of local money {
display "`currency'"
}Veamos como iterar sobre una lista de variables:
* Sobre lista de variables
foreach var of varlist mpg weight-turn {
quietly summarize `var' summarize `var' if `var' > r(mean)
}Veamos como iterar sobre una lista de de nuevas variables:
* Sobre lista de nuevas variables
foreach var of newlist z1-z20 {
generate `var' = runiform()
}Veamos como iterar sobre una lista de números:
foreach num of numlist 1 4/8 13(2)21 103 {
display `num'
}3.1.4.2 Combinar macros con iteradores
foreach y forvalues combinados con macros pueden utilizarse para ahorrarnos mucho trabajo. Podemos generar tun conjunto de locales a partir de iteraciones.
use replicate.dta, replace
levelsof cty
local ctries "`r(levels)'"
foreach ctr in `ctries' {
sum hours_t if cty == "`ctr'"
local nombre `ctr' = `r(mean)'
} Como ya hemos visto, el comando levelsof devuelve una lista de todos los valores distintos de una variable categórica y los guarda en la macro r(levels). Esto lo hace en el caso de que nosotros no le asignemos un nombre. Podemos utilizar esta lista para los países y años de nuestra muestra para definir dos iteraciones que recorran todos los valores posibles. Para cada valor resumimos la población y definimos una macro local compuesta por el código de país y el año (por ejemplo, USA1990) que toma el valor de la población en ese año para ese país.
Una aplicación del forvalues:
use gdp4cty, clear
forvalues i = 1/4 {
generate double lngdp'i' = log(gdp'i')
summarize lngdp'i'
}Utilizando dos forvalues:
forvalues y = 1995(2)1999 {
forvalues i = 2(2)4 {
summarize gdp`i'_`y'
}
}foreach y recode:
use gdp4cty, clear
local ctycode 111 112 136 134
local i 0
foreach c of local ctycode{
local ++i
local rc "`rc' (`i'=`c')"
}
display "`rc'"
recode cc `rc', gen(newcc)Loops anidados: foreach y forvalues
use gdp4cty, clear
local country US UK DE FR
local yrlist 1995 1999
forvalues i = 1/4 {
local cnaine: word `i' of `country'
display "`cnaine'"
foreach y of local yrlist {
rename gdp`i'_`y' gdp`cnaine'_`y'
}
}En estos casos es bueno utilizar espacios para hacer el código más amigable. Ojo que a Stata no le interesa esto para ejecutar, es solo una cuestión de estilo.
sysuse auto, clear
foreach y of varlist mpg rep78 headroom trunk weight length {
foreach x of varlist rep78 price displacement gear_ratio foreign {
regress `y' `x'
} También útil para estimar regresiones.
Tokenize: Podemos almacenar los elementos de la lista de países en macros numeradas con tokenize.
use gdp4cty, clear
local country US UK DE FR
local yrlist 1995 1999
local ncty: word count `country'
display "`ncty'"
tokenize `country'
forvalues i = 1/`ncty'{
foreach y of local yrlist {
rename gdp`i'_`y' gdp``i''_`y'
}
}Aquí los nombres de los países se almacenan como valores de las macros numeradas. Debemos referenciar doblemente la macro \(i\). El contenido de esa macro la primera vez que se pasa por el bucle es el número 1. Para acceder al primer código de país, debemos referenciar la macro \(`1'\).
3.1.4.3 While loop
Realiza la iteración o se repite una lista de comandos mientras la condición while sea verdadera. La sintaxis es:
while exp {
hace algo
}¿Cuando es útil? : Cuando no este seguro(a) cuantas veces se realizará la iteración. Notar que si no hay convergencia, va iterar infinitamente.
while reldif (nueva, antigua) > 0.001 {
}También se puede combinar con macros. Es importante utilizar los incrementales:
local i=1
while `i'<=5 {
display "loop number" `i'
local i = `i'+1
}La primera parte define el inicio del contador, mientras que la segunda indica la condición para que sea ejecutado. El local final actualiza (incremental). Si el incremento es unitario podemos utilizar local ++i.
3.1.4.4 Branching
Hacer una cosa en caso de que alguna condición sea cierta y otra cosa en caso de que sea falsa. La sintaxis básica es:
if algo es verdadero {
hacer esto
} else {
hacer lo contrario
}Ejercicio 3.4.2:
Preguntas
- Defina una macro llamada mimacro que sea igual a un número entero aleatorio entre 1 y 99.
- Utilizando
ifyelsemuestre un mensaje que diga si es par o impar.
3.1.4.5 Aplicaciones
Seguir secuencias especiales: creturn posee varias constantes y valores a los que se puede acceder. Por ejemplo:
c(filename)nombre del último nombre del archivo guardado.c(alpha/ALPHA)lista de letras minúsculas/mayusculas.
c(Mons)lista de nombres de los meses abreviados.c(Months)lista de los nombres de los meses no abreviados.c(Wdays)lista de los dias de la semana abreviados a tres caracteres.c(Weekdays)lista de los días de la semana no abreviados.
Con un iterador es posible aplicar estas listas para agregar labels. Suponga que tenemos valores de 1 a 12 que representan meses.
clear all
set obs 12
gen month = _n
tokenize `c(Months)'
forvalues i = 1/12 {
label define monthlab `i' "``i''" , modify
}
label val month monthlab3.1.4.6 Monitorear un loop
Ejemplo proveniente de (Stata tip 41). Cualquier loop puede ser modificado para que muestre su progreso con el comando _dots. Esto es importante para cuando se requieren hacer procesos que toman varias horas y es necesario monitorear avances.
_dots 0, title(Loop ejecutando) reps(75)
forvalues i = 1/75 {
_dots ‘i’ 0
}
----+--- 1 ---+--- 2 ---+--- 3 ---+--- 4 ---+--- 5
.................................................. 50
.........................El primer comando _dots establece las lineas. Titulo y número de repeticiones son opcionales. reps solo acepta enteros como argumento. _dots ‘i’ 0 tiene dos elementos:
- El primer argumento es el número de repetición, que registra el número de intentos en curso. En el ejemplo, esta automáticamente determinado por el loop.
- El segundo argumento es el código de retorno, el cual indica el tipo de símbolo. En el ejemplo tenemos un 0.
- Los códigos de retorno alternativos producen una “s” (-1), “.” (), “x” roja (1), una “e” (2), una “n” (3) o un “?” (cualquier otro valor).
Ejemplo no numérico: La idea es definir una macro local para que actue como un contador.
sysuse auto
_dots 0, reps(10)
foreach var of varlist price - gear_ratio {
sum `var', d
local i = `i'+1
_dots `i' 0
}Contar repeticiones:
- El número de repeticiones en
repno es calculado por_dots. Es necesario contar manualmente las variables e introducir el número. - Esto lo vamos a hacer con la ayuda de una función de macro extendida
sizeof. unabpermite ingresar una lista de variable abreviada y expandirla, de forma tal de que la pueda contar.
sysuse auto
unab myvars : price - gear_ratio
local N : list sizeof myvars
_dots 0, reps(`N')
foreach var of varlist `myvars' {
...
local i = `i'+1
_dots `i' 0
}Un ejemplo más complejo es:
noisily _dots 0, title(Looping until 70 successes...)
local rep 1
local nsuccess 0
while ‘nsuccess’ < 70 {
local fail = uniform() < .2
local nsuccess = ‘nsuccess’ + (‘fail’ == 0)
noisily _dots ‘rep++’ ‘fail’
}Se ejecuta hasta que logre 70 aciertos. En este ejemplo artificial, cada iteración tiene un éxito aleatorio con una probabilidad del 80%. Los éxitos se indican con un punto (.) y los fracasos con una x.
3.1.5 Manejo de bases de datos
3.1.5.1 Prefijo: by
Los prefijos en Stata ejecutan tareas repetitivas sin la necesidad de especificar el rango de valores sobre la tarea que es ejecutada. Un prefijo muy conocido es by. Por ejemplo, by varlist [, sort]: command. command es repetido para cada valor de la variable. Es más, repeticiones siguen el orden de la variable sea string o numeric.
use bpress, clear
bysort sex agegrp: summarize bp 3.1.5.2 Prefijo: xi
xi es útil para cuando queremos producir un variable indicador para las observaciones que son distintas entre si.
xi i.agegrpEl ejemplo le esta diciendo a Stata que genere variables indicadores. Esto es muy útil para reducir los códigos.
Interpretando prefijo xi: xi es comúnmente utilizado como un prefijo. La principal ventaja es cuando existen múltiples interacciones entre las variables.
* Caso 1: incluye indicadores de ambas variables.
xi: regress bp i.agegrp i.sex
* Caso 2: incluye además interacciones entre ellas.
xi: regress bp i.agegrp*i.sex
* Caso 3: Interactúa una variable continua con una discreta.
xi: regress bp i.agegrp*bp0
* Caso 4: Incluye solo interacciones con variable continua (además de principal).
xi: regress bp i.agegrp|bp0 3.1.5.3 Prefijo: statsby
statsby permite ampliar by. Este último tiene la limitación de permitir únicamente un comando.
statsby mean=r(mean) sd=r(sd) n=r(N), by(agegrp sex): summarize bpSe produce una nueva base de datos con una observación por grupo con los estadísticos incorporados. Útil para calcular estadística descriptiva.
3.1.5.4 Prefijo: rolling
statsby permite obtener estadísticas para sub-muestras que no se traslapan. rolling sirve para sub-muestras traslapadas. Por ejemplo, al trabajar con series de tiempo se quiere calcular estadísticas para datos que están traslapados (el. calcular una media móvil).
Vamos a calcular medias y medianas utilizando una ventana de 90 días:
use ibm, clear
rolling mean=r(mean) median=r(p50), window(90): summarize spx, d
tsset end
tsline meanstart y end indican el inicio y fin de la ventana.
3.1.5.5 Merge y Append
Recomendaciones para utilizar merge
- Especifique siempre el tipo de fusión (1:1, m:1 o 1:m). Si no se especifica el tipo de fusión, se llama a la versión antigua y no robusta de la fusión.
- Nunca haga fusiones de muchos a muchos (m:m), o al menos, sólo hágalo cuando tenga una muy buena razón.
- Incluya siempre la opción
assert()para indicar qué patrón de observaciones coincidentes espera. - Incluya siempre la opción
keep()para indicar qué observaciones deben conservarse del conjunto de datos fusionados. - Siempre que sea posible, incluya la opción
keepusing()y enumere explícitamente qué variables pretende añadir al conjunto de datos; puede incluir esta opción incluso cuando mantenga todas las variables de los datos utilizados. - Utilice la opción
nogen, excepto cuando piense utilizar explícitamente la variable_mergemás adelante. Nunca debe guardar un conjunto de datos que tenga_merge; si necesita esta variable más adelante, dele un nombre más informativo.
Con respecto a especificar _merge y assert notar que:
merge ..., assert(match master) keep(match)
* Es equivalente a:
merge ...
assert _merge==1 | _merge==3
keep if _merge==3Append con ciudado:
- El comando
appendes muy útil para manejos de bases de datos. Una precaución común es con respecto al nombre de las variables. Si dos variables (ej. PRECIO y precio) difieren, se generaran dos columnas nuevas al hacer elappenden vez de una. - Una precaución un poco menos conocida guarda relación con el tipo de variables. ¿Qué ocurre si dos variables se llaman igual, pero estan guardadas en formatos distintos?
- En este caso, el orden en el cual se combine la base de datos va a importar y puede generar diferencias al momento de pegar datos. Esto es especialmente importante cuando una variable esta guardada en numérico en una base de datos y en
stringen la otra.
Veamos un ejemplo con la base auto.dta. Vamos a crear dos bases de datos según la procedencia de los autos y ejecutar el comando append.
sysuse auto
drop if foreign
save autodom
sysuse auto
drop if !foreign
rename foreign nondom
generate str foreign = "foreign" if nondom
save autofor
use autdom
append using autofor
describe foreign Notar que append genera el siguiente mensaje: foreign is str 7 in using data byt will be byte now. Noten que el contenido de la variable string se ha perdido: 22 casos son ahora missing.
¿Qué ocurre si hacemos el proceso al revés? Vamos a cargar autos extranjeros y le vamos a pegar autos domésticos:
use autfor
append using autodom, force
describe foreign
codebook foreignEl formato de los datos de la primer base de datos manda.
* No utilizar force sin cuidado.
* Con distintos tipos de datos, append es sensible al orden en que los archivos son pegados. Tener cuidado y revisar consistencia en los datos. Hacer test aquí tambíen es importante.