Sesión 2. Manipulación de datos y archivos

José-Ignacio Antón


Inicio      Sesión 1      Sesión 2      Sesión 3      Sesión 4      Sesión 5      Ejercicios


1. Operaciones de fusión horizontal de archivos

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).

1.1. Fusiones de bases de datos de una observación a otra observación

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.

1.2. Fusiones de bases de datos de varias observaciones a una observación (o viceversa)

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).

2. Operaciones de fusión vertical de archivos

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

3. Crear una base de datos con estadísticos descriptivos

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)

4. Cambiar la disposición de los datos

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(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(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
─────────────────────────────────────────────────────────────────────────────

5. Nociones básicas de programación: preserve, restore y el uso de macros y bucles

En 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).

5.1. El uso de 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.

5.2. El uso de macros: 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

5.3 El uso de bucles

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

Referencias

Baum, C. F. (2016). An introduction to Stata programming (2nd ed.). Stata Press.
Escobar, M., Fernández-Macías, E., & Bernardi, F. (2012). Análisis de datos con Stata (2nd ed.). Centro de Investigaciones Sociólogicas.
Kohler, U., & Kreuter, F. (2012). Data analysis using Stata (3rd ed.). Stata Press.