Inicio Sesión 1 Sesión 2 Sesión 3 Sesión 4 Sesión 5 Ejercicios
Una de las operaciones más utilizadas en Stata
para manipular archivos es la instrucción merge
, que permite fusionar dos archivos a partir de ciertas variables comunes. Ejemplos típicos son la fusión de distintas bases de datos con características de los inviduos o una base de datos con características de los invidividuos que queremos fusionar con una bases de datos con características de los hogares.
Para ilustrar estos comandos, vamos a emplear los archivos de la ECV 2018, en concreto, el archivo básico de personas (ecv18r.dta
), el archivo básico de hogares (ecv18d.dta
), el archivo detallado de personas (ecv18p.dta
) y el archivo detallado de hogares (ecv18h.dta
), que se encuentran en la carpeta sesión2
. Lo primer de todo, por lo tanto, es seleccionar el directorio de trabajo
. cd "D:\Dropbox\curso_stata\sesión2" D:\Dropbox\curso_stata\sesión2
Dos posibles referencias que cubren el contenido de esta sesión son Escobar et al. (2012) y Kohler & Kreuter (2012).
Antes de nada, debemos tener en cuenta que en las bases de datos hay variables que actúan como identificadores y que nos permiten relacionar los diferentes archivos. En ocasiones, la identificación de una unidad (hogar, persona, empresa, muestra, etc.) viene dada por una variable y, en otras, por la combinación de varias variables.
En primer lugar, vamos a fusionar el archivo básico de hogares (ecv18d.dta
) con el archivo detallado de hogares (ecv18h.dta
). El primero contiene variables muy básicas del hogar (e.g., localización), mientras que el segundo incluye las respuestas al cuestionario detallado de la ECV a los hogares sobre distintas dimensiones (renta, condiciones de la vivienda, etc.). La variable de enlace en este caso es el identificador del hogar (hid
). Esta variable aparece como db030
en el primer archivo y como hb030
, en el segundo. En ambos casos, las hemos renombrado empleando un nombre común, hid
.
Procedemos en tres pasos:
Paso 1. Abrimos una de las bases de datos (master file
)
Paso 2. Ejecutamos la instrucción merge
para fusionar la primera base con la segunda (using file
)
merge 1:1 varlist using filename [, options]
Paso 3. Comprobamos que la operación se ha realizado correctamente (recurriendo a la variable creada, automáticamente, _merge
). Esta variable puede tomar tres valores: el valor 3 indica que la observación se encuentra en las dos bases de datos (match
); el valor 1, que solo se encuentra en la base de datos master
y el valor 2, que únicamente la encontramos en la base de datos using
. Dependiendo de nuestros objetivos, podemos quedarnos solo con las observaciones que se encuentran en ambos archivos y borrar el resto de observaciones.
Así, en nuestro ejemplo, abrimos la base de datos
. // Abrimos la base de datos . . use "ecv18d.dta", clear (ECV 2018-archivo D) . . // Realizamos la fusión . . merge 1:1 hid using "ecv18h.dta" Result Number of obs ───────────────────────────────────────── Not matched 0 Matched 13,368 (_merge==3) ───────────────────────────────────────── . . // Comprobamos que se ha realizado correctamente . . tabulate _merge Matching result from │ merge │ Freq. Percent Cum. ────────────────────────┼─────────────────────────────────── Matched (3) │ 13,368 100.00 100.00 ────────────────────────┼─────────────────────────────────── Total │ 13,368 100.00
Observamos que las observaciones se encuentran en ambas bases de datos simultáneamente.
A continuación, fusionamos la base de datos con información básica de personas (ecv18r.dta
) con la base de datos con información detallada (ecv18p.dta
). De acuerdo a la documentación de la encuestas y nuestro etiquetado, la variable de enlace es el identificador personal (pid
), que corresponde a las variables de identificador del hogar en cada archivo (rb030
y pb030
, respectivamente). Esta variable, según la documentación está formada porque
\[ \text{pid} = 100 \cdot \text{hid} + \text{nº de 0 a 10 indicando el número de la persona en el hogar}\]
Procedemos como sigue:
. // Abrimos la base de datos . . use "ecv18r.dta", clear (ECV 2018-archivo R) . . // Realizamos la fusión . . merge 1:1 pid using "ecv18p.dta" (label anonac_lab already defined) (label sexo_lab already defined) Result Number of obs ───────────────────────────────────────── Not matched 5,362 from master 5,362 (_merge==1) from using 0 (_merge==2) Matched 28,372 (_merge==3) ───────────────────────────────────────── . . // Comprobamos que se ha realizado correctamente . . tabulate _merge Matching result from │ merge │ Freq. Percent Cum. ────────────────────────┼─────────────────────────────────── Master only (1) │ 5,362 15.89 15.89 Matched (3) │ 28,372 84.11 100.00 ────────────────────────┼─────────────────────────────────── Total │ 33,734 100.00
En este caso, observamos que hay observaciones que solo aparecen en la base master
. ¿Existe un error? No, lo que ocurre es que la base de datos con información básica incluye a todas las personas, mientras que la que comprende información detallada, solo a los mayores de 16 años. No obstante, la variable _merge
nos permite distinguir errores de otras circunstancias.
En ocasiones, precisamos fusionar una base de datos a un cierto nivel (e.g., personas) con otra base de datos con información a nivel superior (e.g., hogares o regiones). Para realizar este tipo de operación empleamos
merge m:1 varlist using filename [, options]
En nuestro caso, vamos a fusionar la base de datos de personas con información básica (ecv18r.dta
) con la base de datos de los hogares con información básica (ecv18d.dta
). La variable de enlace, común en ambas bases, es el identificador del hogar (hid
). Según la documentación, el identificador personal está compuesto del identificador laboral más el número de orden de la persona dentro del hogar. En los ficheros de personas, hemos creado un identificador del hogar empleando generate int hid = pid/100
, por lo que tenemos dicha variable. La fusión, en este caso, es perfecta, pero, en muchas ocasiones, hay problemas de no respuesta, errores de codificación, etc. y es habitual que nos tengamos que quedar solo con aquellos datos que enlazan perfectamente (_merge == 3
).
. // Abrimos la base de datos . . use "ecv18r.dta", clear (ECV 2018-archivo R) . . // Realizamos la fusión . . merge m:1 hid using "ecv18d.dta" Result Number of obs ───────────────────────────────────────── Not matched 0 Matched 33,734 (_merge==3) ───────────────────────────────────────── . . // Comprobamos que se ha realizado correctamente . . tabulate _merge Matching result from │ merge │ Freq. Percent Cum. ────────────────────────┼─────────────────────────────────── Matched (3) │ 33,734 100.00 100.00 ────────────────────────┼─────────────────────────────────── Total │ 33,734 100.00
Podemos, fácilmente, fusionar todas las bases de datos en un único fichero (y, si queremos, ordenar la base de datos posteriormente). Debemos eliminar antes de cada fusión la variable _merge
(o no crearla al realizar la fusión).
. // Fusionamos los archivos de personas . . use "ecv18r.dta", clear (ECV 2018-archivo R) . merge 1:1 pid using "ecv18p.dta", nogenerate (label anonac_lab already defined) (label sexo_lab already defined) Result Number of obs ───────────────────────────────────────── Not matched 5,362 from master 5,362 from using 0 Matched 28,372 ───────────────────────────────────────── . . // Fusionamos con los archivos de hogares . . merge m:1 hid using "ecv18d.dta", nogenerate Result Number of obs ───────────────────────────────────────── Not matched 0 Matched 33,734 ───────────────────────────────────────── . merge m:1 hid using "ecv18h.dta", nogenerate Result Number of obs ───────────────────────────────────────── Not matched 0 Matched 33,734 ─────────────────────────────────────────
Importante: Nunca debe emplearse la fusión merge m:m
. Es preferible emplear la función joinby
(help joinby
).
El comando append
nos permite unir archivos que contienen las mismas variables pero referidas a distintas unidades de análisis. Por ejemplo, podemos fusionar la base de datos de la ECV del año 2018 (ecv18
) con otras de años anteriores, como la base de datos del año 2017 (ecv17
) y 2016 (ecv16
). El procedimiento es el siguiente:
Paso 1. Abrimos uno de los archivos.
Paso 2. Con el comando, append
agregamos el resto de archivos.
append using filename [filename …] [, options]
En nuestro caso, podemos proceder Así
. // Abrimos el archivo de la ECV de 2016 . . use "ecv16.dta", clear (ECV 2016) . . // Agregamos los años 2017 y 2018 . . append using "ecv17.dta" "ecv18.dta" (label anonac_lab already defined) (label sexo_lab already defined) (label sithogar_lab already defined) (label sitact_lab already defined) (label hbajosalario_lab already defined) (label ecivil_lab already defined) (label phecho_lab already defined) (label paisnac_lab already defined) (label nacionalidad_lab already defined) (label cursaeduc already defined) (label nivelcursa_lab already defined) (label educ_lab already defined) (label htrabajo_lab already defined) (label busctrabajo_lab already defined) (label disptrabajo_lab already defined) (label sitprof_lab already defined) (label menos30h_lab already defined) (label ntrabajadores_lab already defined) (label contrato_lab already defined) (label supervisor_lab already defined) (label cambiotrabajo_lab already defined) (label motivocambio_lab already defined) (label cambioact_lab already defined) (label act_lab already defined) (label salud_lab already defined) (label cronico_lab already defined) (label limitacion_lab already defined) (label consulta_lab already defined) (label motconsulta_lab already defined) (label consultadentista_lab already defined) (label motdentista_lab already defined) (label ayulimit_lab already defined) (label privacion_lab already defined) (label region_lab already defined) (label urb_lab already defined) (label hrethip_lab already defined) (label hretfact_lab already defined) (label hvaca_lab already defined) (label hcomida already defined) (label hgastos_lab already defined) (label htelef_lab already defined) (label hpc_lab already defined) (label hlavadora_lab already defined) (label hcoche_lab already defined) (label hcapacidad_lab already defined) (label hcargagastos_lab already defined) (label hcargaprest_lab already defined) (label hluz_lab already defined) (label hruidos_lab already defined) (label hcontam_lab already defined) (label hdelin_lab already defined) (label hvivienda_lab already defined) (label htenencia_lab already defined) (label hnhabit_lab already defined) (label hprobl_lab already defined) (label htemp_lab already defined) (label hducha_lab already defined) (label hinodoro_lab already defined) (label hayuamigos_lab already defined) (label hayuorg_lab already defined) (label htipohogar_lab already defined) (label hpobreza_lab already defined) (label hmuebles_lab already defined) (label hmuebles_lab already defined) (label hpobreza_lab already defined) (label htipohogar_lab already defined) (label hayuorg_lab already defined) (label hayuamigos_lab already defined) (label hinodoro_lab already defined) (label hducha_lab already defined) (label htemp_lab already defined) (label hprobl_lab already defined) (label hnhabit_lab already defined) (label htenencia_lab already defined) (label hvivienda_lab already defined) (label hdelin_lab already defined) (label hcontam_lab already defined) (label hruidos_lab already defined) (label hluz_lab already defined) (label hcargaprest_lab already defined) (label hcargagastos_lab already defined) (label hcapacidad_lab already defined) (label hcoche_lab already defined) (label hlavadora_lab already defined) (label hpc_lab already defined) (label htelef_lab already defined) (label hgastos_lab already defined) (label hcomida already defined) (label hvaca_lab already defined) (label hretfact_lab already defined) (label hrethip_lab already defined) (label urb_lab already defined) (label region_lab already defined) (label privacion_lab already defined) (label ayulimit_lab already defined) (label motdentista_lab already defined) (label consultadentista_lab already defined) (label motconsulta_lab already defined) (label consulta_lab already defined) (label limitacion_lab already defined) (label cronico_lab already defined) (label salud_lab already defined) (label act_lab already defined) (label cambioact_lab already defined) (label motivocambio_lab already defined) (label cambiotrabajo_lab already defined) (label supervisor_lab already defined) (label contrato_lab already defined) (label ntrabajadores_lab already defined) (label menos30h_lab already defined) (label sitprof_lab already defined) (label disptrabajo_lab already defined) (label busctrabajo_lab already defined) (label htrabajo_lab already defined) (label educ_lab already defined) (label nivelcursa_lab already defined) (label cursaeduc already defined) (label nacionalidad_lab already defined) (label paisnac_lab already defined) (label phecho_lab already defined) (label ecivil_lab already defined) (label hbajosalario_lab already defined) (label sitact_lab already defined) (label sithogar_lab already defined) (label sexo_lab already defined) (label anonac_lab already defined) . . // Podemos comprobar cómo tenemos información de los tres años . . tabulate ano Año de la │ encuesta │ Freq. Percent Cum. ────────────┼─────────────────────────────────── 2016 │ 36,380 34.64 34.64 2017 │ 34,911 33.24 67.88 2018 │ 33,734 32.12 100.00 ────────────┼─────────────────────────────────── Total │ 105,025 100.00
Esta tarea, si bien se puede realizar combinando otros comandos (egen
, merge
y append
) es mucho más sencilla a través de la potente instrucción collapse
:
collapse clist [if] [in] [weight] [, options]
donde clist
viene dado por
[(stat)] varlist [ [(stat)] … ]
[(stat)] target_var=varname [target_var=varname …] [ [(stat)] …]
El comando admite el cálculo de un amplio conjunto de estadísticos descriptivos (stat
) y permite usar ponderaciones:
mean means (default)
median medians
p1 1st percentile
p2 2nd percentile
... 3rd-49th percentiles
p50 50th percentile (same as median)
... 51st-97th percentiles
p98 98th percentile
p99 99th percentile
sd standard deviations
semean standard error of the mean (sd/sqrt(n))
sebinomial standard error of the mean, binomial (sqrt(p(1-p)/n))
sepoisson standard error of the mean, Poisson (sqrt(mean/n))
sum sums
rawsum sums, ignoring optionally specified weight except observations with a weight of zero are excluded
count number of nonmissing observations
percent percentage of nonmissing observations
max maximums
min minimums
iqr interquartile range
first first value
last last value
firstnm first nonmissing value
lastnm last nonmissing value
Por ejemplo, vamos a crear un archivo que contenga el salario medio por sexo y año.
. // Seleccionamos los trabajadores asalariados únicamente . . generate rentaasa = rentamonasag + rentanomonasag (16,671 missing values generated) . generate nmesesasa = nmesesasatc + 0.5*nmesesasatp (17,397 missing values generated) . keep if rentaasa > 0 & rentaasa < . (61,114 observations deleted) . keep if nmesesasa > 0 & nmesesasa < . (8,361 observations deleted) . . // Creamos el salario bruto mensual de los trabajadores . . generate salario = rentaasa/nmesesasa . label variable salario "Salario bruto mensual" . . // Generamos una base de datos con el salario medio por Comunidad Autónoma y año . . collapse (mean) salariomed = salario, by(ano sexo)
En muchas ocasiones, especialmente cuando trabajamos con datos de panel, resulta tremendamente útil cambiar la disposición de los datos que tenemos. Por ejemplo, en nuestra base de datos tenemos el salario medio por sexo y año. El formato (llamado long
) es el siguiente:
. sort sexo ano . list sexo ano salariomed ┌──────────────────────────┐ │ sexo ano salari~d │ ├──────────────────────────┤ 1. │ Hombre 2016 2285.98 │ 2. │ Hombre 2017 2200.433 │ 3. │ Hombre 2018 2198.547 │ 4. │ Mujer 2016 1877.008 │ 5. │ Mujer 2017 1833.733 │ ├──────────────────────────┤ 6. │ Mujer 2018 1854.421 │ └──────────────────────────┘
Para calcular cuál es la evolución del salario medio por sexo, para ello, sería más fácil disponer de tres variables que recojan el salario, una para cada año (formato wide
). El comando reshape
funciona de la siguiente forma:
reshape wide stub, i(i) j(
En nuestro caso,
. // Cambiamos la disposición de long a wide . . reshape wide salariomed, i(sexo) j(ano) (j = 2016 2017 2018) Data Long -> Wide ───────────────────────────────────────────────────────────────────────────── Number of observations 6 -> 2 Number of variables 3 -> 4 j variable (3 values) ano -> (dropped) xij variables: salariomed -> salariomed2016 salariomed2017 salariomed2018 ───────────────────────────────────────────────────────────────────────────── . . // Calculamos el crecimiento del salario de 2016 a 2018 . . generate cambio1618 = 100*(salariomed2018 - salariomed2016)/salariomed2016 . label var cambio1618 "Cambio porcentual del salario (2016-2018)" . . // Podemos ver cómo se ha creado la nueva variable . . list sexo salariomed2016 salariomed2018 cambio1618 ┌──────────────────────────────────────────┐ │ sexo sal~2016 sal~2018 camb~1618 │ ├──────────────────────────────────────────┤ 1. │ Hombre 2285.98 2198.547 -3.824764 │ 2. │ Mujer 1877.008 1854.421 -1.203314 │ └──────────────────────────────────────────┘
Podemos volver al formato long
de forma análoga:
reshape long stub, i(i) j(
Así,
. // Cambiamos la disposición de long a wide . . reshape long salariomed, i(sexo) j(ano) (j = 2016 2017 2018) Data Wide -> Long ───────────────────────────────────────────────────────────────────────────── Number of observations 2 -> 6 Number of variables 5 -> 4 j variable (3 values) -> ano xij variables: salariomed2016 salariomed2017 salariomed2018-> salariomed ─────────────────────────────────────────────────────────────────────────────
preserve
, restore
y el uso de macros y buclesEn esta sección, vamos a revisar una serie de instrucciones que se utilizan fundamentalmente en programación (e.g., en la elaboración de archivos .do
). Aunque algunos también pueden emplearse de forma interactiva, en otros, esta estrategia carece de sentido, ya que las macros creadas desaparecen cuando se termina de ejecutar el programa. Aquí únicamente haremos una primera aproximación. Para más detalles, puede consultarse, por ejemplo, Baum (2016).
preserve
y restore
En ocasiones, es necesario volver a una versión previa de los datos después de realizar operaciones. Para ello podemos valernos de dos comandos muy útiles, preserve
y restore
. Al introducir preserve
indicamos a Stata
que, cuando introduzcamos el comando restore
, debe volver a los datos justo antes de la introducción de este comando. Estas instrucciones son particularmente de interés cuando tenemos que realizar operaciones en las que eliminemos observaciones o variables. Así, por ejemplo, con la base de datos anterior, podemos eliminar una de las variables y, posteriormente, volver a la base de datos original.
. describe Contains data Observations: 6 ECV 2016 Variables: 4 ──────────────────────────────────────────────────────────────────────────────────────────── Variable Storage Display Value name type format label Variable label ──────────────────────────────────────────────────────────────────────────────────────────── sexo byte %8.0g sexo_lab Sexo ano int %10.0g Año de la encuesta salariomed float %9.0g (mean) salario cambio1618 float %9.0g Cambio porcentual del salario (2016-2018) ──────────────────────────────────────────────────────────────────────────────────────────── Sorted by: sexo ano Note: Dataset has changed since last saved. . . preserve . . // Eliminamos la variable sexo . . drop sexo . . describe Contains data Observations: 6 ECV 2016 Variables: 3 ───────────────────────────────────────────────────────────────────────────────────────────── Variable Storage Display Value name type format label Variable label ───────────────────────────────────────────────────────────────────────────────────────────── ano int %10.0g Año de la encuesta salariomed float %9.0g (mean) salario cambio1618 float %9.0g Cambio porcentual del salario (2016-2018) ───────────────────────────────────────────────────────────────────────────────────────────── Sorted by: Note: Dataset has changed since last saved. . . restore . . describe Contains data Observations: 6 ECV 2016 Variables: 4 ─────────────────────────────────────────────────────────────────────────────────────────── Variable Storage Display Value name type format label Variable label ─────────────────────────────────────────────────────────────────────────────────────────── sexo byte %8.0g sexo_lab Sexo ano int %10.0g Año de la encuesta salariomed float %9.0g (mean) salario cambio1618 float %9.0g Cambio porcentual del salario (2016-2018) ─────────────────────────────────────────────────────────────────────────────────────────── Sorted by: sexo ano Note: Dataset has changed since last saved.
local
, global
, tempname
, tempvar
y tempfile
global
asigna a una macro global (se conserva hasta que se cierre Stata
) cadenas de caracteres. Se emplea habitualmente para crear listas de variables (e.g., regresores como variables independientes a introducir en una regresión). Para referirnos a estas macros, debemos utilizar $
.
local
asigna a una macro local (se conserva hasta que se ejecuta el archivo .do
) cadenas de caracteres y tiene un funcionamiento similar a global
. Para invocar una macro creada, debemos hacerlo entre los caracteres `
y '
.
tempvar
crea varaibles temporales en una base de datos que desaparecen al concluir el programa o el archivo .do
.
tempname
cumple la misma función, pero con matrices o escalares.
tempfile
funciona de forma análoga para nombres de archivos.
Así, por ejemplo, podemos crear una macro global que incluya la variable salariomed
, podemos llamarla var1
y calcular los estadísticos descriptivos de var1
.
. global var1 "salariomed" . . summarize $var1 Variable │ Obs Mean Std. dev. Min Max ─────────────┼───────────────────────────────────────────────────────── salariomed │ 6 2041.687 207.3245 1833.733 2285.98
El tercer elemento clave en términos de programación son los bucles, que, a través de macros locales, nos permiten realizar operaciones de forma repetida y, de esa forma, programar de forma eficiente. Los principales bucles que podemos emplear son los siguientes:
foreach lname in any_list {
commands referring to `lname’
}
foreach lname of local lmacname {
commands referring to `lname’
}
foreach lname of global gmacname {
commands referring to `lname’
}
foreach lname of varlist varlist {
commands referring to `lname’
}
foreach lname of newlist newvarlist {
commands referring to `lname’
}
foreach lname of numlist numlist {
commands referring to `lname’
}
forvalues lname = range {
commands referring to `lname’
}
Podemos calcular a modo de ejemplo la media del salario para cada uno de los 3 años en la muestra:
. forvalues i=2016(1)2018{ 2. summarize salariomed if ano == `i' 3. } Variable │ Obs Mean Std. dev. Min Max ─────────────┼───────────────────────────────────────────────────────── salariomed │ 2 2081.494 289.1874 1877.008 2285.98 Variable │ Obs Mean Std. dev. Min Max ─────────────┼───────────────────────────────────────────────────────── salariomed │ 2 2017.083 259.296 1833.733 2200.433 Variable │ Obs Mean Std. dev. Min Max ─────────────┼───────────────────────────────────────────────────────── salariomed │ 2 2026.484 243.3336 1854.421 2198.547