13 min read

Movilidad educativa intergeneracional en Argentica

Introducción

Las bases de datos de la ENES tienen abundante información sobre las personas y los hogares en los que esas personas viven o vivieron. Muchas preguntas de interés sociológico sobre la transmisión de las desigualdades requieren este tipo de datos. En este caso trabajaremos con una pregunta muy simple ¿Cómo es la relación entrenivel educativo de una persona y el nivel educativo del Principal Sustento del Hogar (PSH) en el que vivió? Una forma de responderla es creando una tabla de contingencia en cuyas filas se ubique el nivel educativo de la persona y en las columnas el nivel educativo del PSH del hogar en el que vive/vivió. En apariencia esto es simple, la complicaciones comienzan cuando verificamos que en la base de datos no tenemos una variable que registre el nivel educativo del PSH de cada persona. La información está, solo que dispersa en múltiples variables y es necesario reunirla. Esta entrada se enfoca en el proceso de manejo de datos para crear la variable nivel_ed_psh, en la que se registra el máximo nivel educativo alcanzado por el Principal Sustento del Hogar del hogar en el que esa persona vive o vivió. Lo haremos creando bases de datos parciales en las que se lleva a cabo la imputación de la variable según aplique y en el uso de joins por claves para reunir toda la información al final.

El problema

La variable nivel_ed_psh no existe, pero la información para crear está disponible.

  • Para PSH y cónyugue de PSH hay una medición directa. En la base de datos de hogares las variables v241a y v244a reportan el máximo nivel educativo alcanzado PSH y cónyugue respectivamente. La columna v111 de la base de datos personas clasifica a las peronas por Parentesco con el PSH, por lo que podemos usarla para filtrar estos casos.

  • Para quienes no son PSH o cónyugue de PSH no tenemos esta información directamente consignada. Sin embargo sabemos que cada persona pertenece a un hogar y podemos identificar al PSH de ese hogar y consultar el máximo nivel educativo de esa persona en la variable nivel_ed. Así imputamos un valor de nivel educativo del PSH para sus hijos/hijas, hijastros y hijastras. Los valores que obtenemos no son exactamente los mismos que en el caso anterior, ya que las preguntas v241a y v244a registran en máximo nivel educativo del PSH a los 15 años de edad de la persona. En esta imputación por hogar las edades de las personas no son necesariamente 15 años al registro de la escolaridad del PSH, en realidad es la edad que tienen al momento de la encuesta. Esta situación no es la ideal, pero son los datos que hay.

  • En el caso de nietos se imputará también el nivel educativo del PSH del hogar. Esto es consistente con la forma en la que está medida las variables v241a y v244a que usamos como referencia. Es decir, el análisis subsiguiente no será sobre movilidad educativa entre padres/madres e hijos/hijas, sino entre el nivel educativo del PSH del hogar orígen y la persona al momento de la encuesta.

  • Con el objetivo de ampliar tanto como sea posible al imputación de esta variable para adultos se imputará a quienes tienen relación de parentesco “Hermano/a” de PSH el mismo nivel educativo del PSH de orígen del PSH actual. En términos prácticos, si un PSH indica que a los 15 años el PSH del hogar en el que vivía tenía educación primaria a su hermano/a se le inputará el mismo valor. Se asume, por lo tanto, que vivían en el mismo hogar, aún cuando pudiera no ser el caso.

Enfoque del problema

Se enfoca el problema como un problema de imputación selectiva por subconjuntos. Para cada categoría de parentesco registrada en v111 se buscará una solución ad hoc. Resuelto el problema para cada subconjunto estos se reúnen en una sola tabla y se unen con el resto de los datos de la base personas con un join que usa las variables clave nocues, nhog y miembro. Estas variables permiten identificar a cada individuo.

Carga de datos

library(tidyverse)
library(haven)
library(tidyverse)


# base de hogares
hogares <- read_sav("../../static/docs/datos/ENES_Hogares_version_final.sav")

#base de personas
personas <- read_sav("../../static/docs/datos/ENES_Personas_version_final.sav")

# base unida de personas y hogares
unida <- left_join(personas, hogares, by = c("nocues", "nhog")) %>% 
  rename(fcalib_hog = f_calib3.y, 
         fcalib_per = f_calib3.x)

diccionario_hogares <- tibble(nombre = names(hogares), 
                                etiqueta = map_chr(hogares, attr, "label"))

diccionario_personas  <- tibble(nombre = names(personas), 
                                etiqueta = map_chr(personas, attr, "label"))

diccionario <- bind_rows(diccionario_hogares, diccionario_personas)

renombrar <- function(x) {
  rename_all(x, ~diccionario$etiqueta[match(., diccionario$nombre)])
}

Diagnóstico de los datos

Antes de comenzar con las operaciones de imputación es buena idea saber qué esperamos del resultado. Como la imputación se hará por grupos de relación de parentesco con PSH vamos a contar cuantas filas son imputables (por pertenecer a los grupos de parentesco en los que tenemos información) y cuantas inimputables. No utilizaremos el ponderador muestral, aquí nos interesan los datos de encuestados y encuestadas.

\(n\) por relación de parentescto

# Una lista de listas de recodificación, más adelante agregaremos elementos.

reco <- list(
imputabilidad = list(
imputables = c("PSH", "Cónyuge", 
               "Hijo/a (incluye hijastro/a)", 
               "Hermano/a", "Nieto/a"),
inimputables = c("Yerno/Nuera", "Cuñado/a", 
                 "Padre/Madre/Suegro/Suegra", "Otros familiares", 
                 "Servicio doméstico", "Otros no familiares") )
)

personas %>% 
  select(v111) %>% 
  count(v111) %>% 
  as_factor() %>% 
  knitr::kable(caption = "Frecuencias de relación de parentesco con PSH")
Table 1: Frecuencias de relación de parentesco con PSH
v111 n
PSH 8265
Cónyuge 5093
Hijo/a (incluye hijastro/a) 11274
Yerno/Nuera 259
Hermano/a 327
Nieto/a 1283
Cuñado/a 53
Padre/Madre/Suegro/Suegra 599
Otros familiares 348
Servicio doméstico 8
Otros no familiares 101
personas %>% 
  select(v111) %>% 
  as_factor() %>% 
  mutate(imputabilidad = fct_collapse(v111, !!!reco$imputabilidad)) %>% 
  count(imputabilidad) %>% 
  mutate(proporción = n / sum(n)) %>% 
  knitr::kable(caption = "Proporción de n imputable")
Table 1: Proporción de n imputable
imputabilidad n proporción
imputables 26242 0.9504527
inimputables 1368 0.0495473

Con este procedimiento potencialmente tenemos datos para imputar un 95% de la n. Digo potencialmente porque podrían haber información faltante que reduzca este número, pero es un buen punto de partida. A pesar de una proporción alta hay algunos sesgos que podrían introducirse al hacer esta selecció. Es esperable que los imputados sean un poco más jóvenes que el total, porque no se imputan Madre/Padre de PSH.

Nivel máximo de escolaridad de PSH de hijos/as en el hogar al momento de la entrevista

Pasos:

  1. Crear una tabla con la escolaridad de PSH por hogar
  2. Filtrar en la tabla personas a hijes y nietes de PSH
  3. Join izquierdo por tabla 2, agregando el dato de escolaridad de PSH correspondiente.
left_join(
  
personas %>% 
  select(nocues, nhog, miembro, v111) %>% 
  filter(v111 %in% c(3, 7)),
          
unida %>% 
  select(nocues, nhog, v111, nivel_ed) %>% 
  filter(v111 == 1), 

by = c("nocues", "nhog")) %>% 
  select(nocues, nhog, miembro, parentesco = v111.x, niveled_psh = nivel_ed) %>% 
  as_factor() ->
  niveled_PSH_hijesnietes

# Resultado

niveled_PSH_hijesnietes
## # A tibble: 12,557 x 5
##    nocues  nhog miembro parentesco                  niveled_psh                 
##     <dbl> <dbl>   <dbl> <fct>                       <fct>                       
##  1      1     1       3 Hijo/a (incluye hijastro/a) Universitario incompleto    
##  2      1     1       5 Nieto/a                     Universitario incompleto    
##  3      3     1       6 Hijo/a (incluye hijastro/a) Secundario/Polimodal comple…
##  4      4     1       3 Hijo/a (incluye hijastro/a) Secundario/Polimodal comple…
##  5      4     1       4 Hijo/a (incluye hijastro/a) Secundario/Polimodal comple…
##  6      4     1       5 Hijo/a (incluye hijastro/a) Secundario/Polimodal comple…
##  7      5     1       4 Hijo/a (incluye hijastro/a) Primaria/EGB completo       
##  8      5     1       5 Hijo/a (incluye hijastro/a) Primaria/EGB completo       
##  9      6     1       3 Hijo/a (incluye hijastro/a) Primaria/EGB completo       
## 10      6     1       4 Hijo/a (incluye hijastro/a) Primaria/EGB completo       
## # … with 12,547 more rows

Nivel máximo de escolaridad de PSH de PSH

Este caso es relativamente simple, se filtra a “PSH” y “Hermano/a” y se toma el valor de la variable v241a como niveled_psh.

unida %>% 
  select(nocues, nhog, miembro, v111, v240a ) %>% 
  as_factor() %>% 
  filter(v111 %in% c("PSH", "Hermano/a")) %>% 
  rename(niveled_psh = v240a, parentesco = v111) %>% 
  as_factor() -> niveled_PSH_PSH_o_hermano

Nivel máximo del PSH del cónyugue del PSH

Igual al anterior.

unida %>% 
  select(nocues, nhog, miembro, v111, v244a ) %>% 
  as_factor() %>% 
  filter(v111 == "Cónyuge") %>% 
  rename(niveled_psh = v244a, parentesco = v111) -> niveled_PSH_cónyuge

Variable imputada

Se crea un data.frame con 4 variables: nocues, nhog y miembro para identificación y join con las demás bases de datos y la variable imputada niveled_psh con la información nueva. La variable niveled_psh tiene casos perdidos (NA). Para evitar ulteriores confusiones se los explicita en la categoría Sin información.

niveled_psh <- bind_rows(niveled_PSH_hijesnietes, 
                         niveled_PSH_PSH_o_hermano, 
                         niveled_PSH_cónyuge) %>% 
  mutate(niveled_psh = fct_explicit_na(niveled_psh , "sin_información"))

niveled_psh
## # A tibble: 26,242 x 5
##    nocues  nhog miembro parentesco                  niveled_psh                 
##     <dbl> <dbl>   <dbl> <fct>                       <fct>                       
##  1      1     1       3 Hijo/a (incluye hijastro/a) Universitario incompleto    
##  2      1     1       5 Nieto/a                     Universitario incompleto    
##  3      3     1       6 Hijo/a (incluye hijastro/a) Secundario/Polimodal comple…
##  4      4     1       3 Hijo/a (incluye hijastro/a) Secundario/Polimodal comple…
##  5      4     1       4 Hijo/a (incluye hijastro/a) Secundario/Polimodal comple…
##  6      4     1       5 Hijo/a (incluye hijastro/a) Secundario/Polimodal comple…
##  7      5     1       4 Hijo/a (incluye hijastro/a) Primaria/EGB completo       
##  8      5     1       5 Hijo/a (incluye hijastro/a) Primaria/EGB completo       
##  9      6     1       3 Hijo/a (incluye hijastro/a) Primaria/EGB completo       
## 10      6     1       4 Hijo/a (incluye hijastro/a) Primaria/EGB completo       
## # … with 26,232 more rows

Unión con el resto de los datos

Como el data.frame niveled_psh tiene las columnas de identificación de vivienda, hogar y miembro es muy fácil unirlo con la base de datos de personas. Simplemente hacemos un join por el lado izquierdo en el que obtendremos todas las filas de la base de datos personas y se rellenará con NA (missing) cuando no hay información sobre el nivel educativo del PSH.

left_join(personas, niveled_psh) %>% 
  count(niveled_psh, sort = TRUE) %>% 
  mutate(cat = 1:n())
## # A tibble: 20 x 3
##    niveled_psh                                                           n   cat
##    <fct>                                                             <int> <int>
##  1 Primario                                                           7131     1
##  2 Primaria/EGB completo                                              3350     2
##  3 Secundario/Polimodal completo                                      2611     3
##  4 sin_información                                                    2467     4
##  5 Secundario/Polimodal incompleto                                    2206     5
##  6 Secundario                                                         1962     6
##  7 Primaria/EGB incompleto                                            1652     7
##  8 <NA>                                                               1368     8
##  9 Ninguno                                                            1033     9
## 10 Universitario completo                                              794    10
## 11 Terciario completo                                                  790    11
## 12 Universitario incompleto                                            513    12
## 13 Universitario                                                       472    13
## 14 Terciario                                                           437    14
## 15 Terciario incompleto                                                321    15
## 16 Sin instrucción (incluye nunca asistió o sólo asistió a sala de …   311    16
## 17 EGB                                                                 110    17
## 18 Polimodal                                                            36    18
## 19 Posgrado Universitario                                               32    19
## 20 Educación especial                                                   14    20

Aquí se presentan varios problemas:

  • Hay demasiadas (20) categorías y algunas se superponen. Las variables v241a y v244a no tienen las mismas categorías que nivel_ed. Será necesario compactarlas.
  • Los NA son los casos inimputables, será necesario indicarlo como tal.

Esquemas de recodificación

reco$niveled_psh <-  list(ninguno = c("Sin instrucción (incluye nunca asistió o sólo asistió a sala de 5)", "Primaria/EGB incompleto", "Ninguno"),
             primaria = c( "Primario","Primaria/EGB completo", "Secundario/Polimodal incompleto", "EGB"), 
             secundaria = c("Secundario/Polimodal completo", "Terciario incompleto", "Secundario", "Polimodal"), 
             terciario = c( "Terciario", "Terciario completo", "Universitario incompleto"), 
             universitario = c("Universitario completo", "Universitario", "Posgrado Universitario"), 
             otro = c("Educación especial"))

reco$niveled_psh %>% 
  map_df(~`length<-`(.x, 3)) %>% 
  gather("Código nuevo", "Códigos originales") %>% 
  drop_na() %>%
  knitr::kable(caption = "Recodificación de la variable Nivel Educativo del PSH")
Table 2: Recodificación de la variable Nivel Educativo del PSH
Código nuevo Códigos originales
ninguno Sin instrucción (incluye nunca asistió o sólo asistió a sala de 5)
ninguno Primaria/EGB incompleto
ninguno Ninguno
primaria Primario
primaria Primaria/EGB completo
primaria Secundario/Polimodal incompleto
secundaria Secundario/Polimodal completo
secundaria Terciario incompleto
secundaria Secundario
terciario Terciario
terciario Terciario completo
terciario Universitario incompleto
universitario Universitario completo
universitario Universitario
universitario Posgrado Universitario
otro Educación especial
reco$nivel_ed <- list(ninguno = c("Sin instrucción (incluye nunca asistió o sólo asistió a sala de 5)", "Primaria/EGB incompleto"),
             primaria = c("Primaria/EGB completo", "Secundario/Polimodal incompleto"), 
             secundaria = c("Secundario/Polimodal completo", "Terciario incompleto"), 
             terciario = c("Terciario completo", "Universitario incompleto"), 
             universitario = "Universitario completo", 
             otro = c("Educación especial", "NS/NR"))

reco$nivel_ed %>% 
  map_df(~`length<-`(.x, 2)) %>% 
  gather("Código nuevo", "Códigos originales") %>% 
  drop_na() %>% 
  knitr::kable(caption = "Recodificación de la variable Nivel Educativo de la persona")
Table 2: Recodificación de la variable Nivel Educativo de la persona
Código nuevo Códigos originales
ninguno Sin instrucción (incluye nunca asistió o sólo asistió a sala de 5)
ninguno Primaria/EGB incompleto
primaria Primaria/EGB completo
primaria Secundario/Polimodal incompleto
secundaria Secundario/Polimodal completo
secundaria Terciario incompleto
terciario Terciario completo
terciario Universitario incompleto
universitario Universitario completo
otro Educación especial
otro NS/NR

Movilidad educativa

Tabla de movilidad (toma 1)

left_join(personas, niveled_psh) %>% 
  filter(v108 > 29) %>% 
  select(niveled_psh, nivel_ed, f_calib3, v108) %>% 
  mutate(niveled_psh = as.factor(niveled_psh), 
         nivel_ed = as_factor(nivel_ed),
         niveled_psh = fct_collapse(niveled_psh, !!!reco$niveled_psh ),
         niveled_psh = fct_relevel(niveled_psh, !!!names(reco$niveled_psh)),
         niveled_psh = fct_explicit_na(niveled_psh, "inimputable"),
         nivel_ed = fct_collapse(nivel_ed, !!!reco$nivel_ed), 
         v108 = cut_interval(v108, 3)) %>%
  count(niveled_psh, nivel_ed,  wt = f_calib3) -> nivel_ed_x_nivelel_psh

nivel_ed_x_nivelel_psh %>% 
  spread(nivel_ed, n, 0) %>% 
  knitr::kable(caption = "Frecuencia condicional de nivel educativo de la persona y su PSH.^[Aplica ponderador muestral]")
Table 3: Frecuencia condicional de nivel educativo de la persona y su PSH.1
niveled_psh ninguno primaria secundaria terciario universitario otro
ninguno 426524 655866 267077 71365 18754 3331
primaria 1035109 4096268 2686820 1283041 628661 18776
secundaria 64911 413252 849743 620516 435707 9720
terciario 24426 40481 176891 217953 219170 1204
universitario 6634 23808 102448 207315 339806 358
otro 427 3206 0 1196 0 790
sin_información 570353 1183791 625197 219731 120576 1444
inimputable 322879 416540 198197 82626 33142 3210

Tabla de movilidad (proporción de Nivel educativo del PSH)

Las columnas indican el nivel eductativo del PSH, las filas el nivel educativo de la persona.

Ejp: un 6.4% de las persona mayores de 30 años que lograron educación primaria vivieron/viven en un hogar cuyo PSH alcanzó educación universitaria.

nivel_ed_x_nivelel_psh %>% 
  group_by(niveled_psh) %>% 
  mutate(prop = n / sum(n), 
         prop = scales::percent(prop)) %>% 
  select(-n) %>% 
  spread(niveled_psh, prop, 0) %>% 
    knitr::kable(caption = "Nivel educativo de orígen y destino. Proporción de nivel según el orígen ^[Aplica ponderador muestral]")
Table 4: Nivel educativo de orígen y destino. Proporción de nivel según el orígen 2
nivel_ed ninguno primaria secundaria terciario universitario otro sin_información inimputable
ninguno 29.6% 10.6% 2.71% 3.59% 0.98% 7.6% 21.0% 30.6%
primaria 45.5% 42.0% 17.26% 5.95% 3.50% 57.1% 43.5% 39.4%
secundaria 18.5% 27.6% 35.50% 26.01% 15.06% 0 23.0% 18.8%
terciario 4.9% 13.2% 25.92% 32.05% 30.47% 21.3% 8.1% 7.8%
universitario 1.3% 6.4% 18.20% 32.22% 49.94% 0 4.4% 3.1%
otro 0.2% 0.2% 0.41% 0.18% 0.05% 14.1% 0.1% 0.3%
nivel_ed_x_nivelel_psh %>% 
  group_by(nivel_ed) %>% 
  mutate(prop = n / sum(n), 
         prop = scales::percent(prop)) %>% 
  select(-n) %>% 
  spread(niveled_psh, prop, 0) %>% 
    knitr::kable(caption = "Proporción de orígen según destino^[Aplica ponderador muestral]")
Table 4: Proporción de orígen según destino3
nivel_ed ninguno primaria secundaria terciario universitario otro sin_información inimputable
ninguno 17.40% 42.23% 2.65% 1.00% 0.27% 0.02% 23.27% 13.17%
primaria 9.598% 59.946% 6.048% 0.592% 0.348% 0.047% 17.324% 6.096%
secundaria 5.44% 54.76% 17.32% 3.61% 2.09% 0 12.74% 4.04%
terciario 2.639% 47.454% 22.950% 8.061% 7.668% 0.044% 8.127% 3.056%
universitario 1.04% 35.01% 24.26% 12.20% 18.92% 0 6.71% 1.85%
otro 8.58% 48.35% 25.03% 3.10% 0.92% 2.03% 3.72% 8.27%
library(ggalluvial)
nivel_ed_x_nivelel_psh %>% 
ggplot(aes(y = n, axis1 = niveled_psh, axis2 = nivel_ed)) +
  geom_alluvium(aes(fill = niveled_psh), width = 1/12) +
  geom_stratum(width = 1/12, color = "grey") +
  geom_label(stat = "stratum", infer.label = TRUE) +
  scale_y_continuous(sec.axis = dup_axis(name = "Nivel educativo de la persona")) +
  theme_minimal() +
  theme(legend.position = "none", 
        axis.text = element_blank()) +
  labs(x = NULL, 
       y = "Nivel educativo del PSH", 
       title = "Movilidad educativa intergeneracional")

library(ggforce)

left_join(personas, niveled_psh) %>% 
  select(niveled_psh, nivel_ed, v108) %>% 
  filter(v108 > 29) %>% 
  mutate(niveled_psh = as.factor(niveled_psh), 
         nivel_ed = as_factor(nivel_ed),
         niveled_psh = fct_collapse(niveled_psh, !!!reco$niveled_psh ),
         niveled_psh = fct_relevel(niveled_psh, !!!names(reco$niveled_psh)),
         niveled_psh = fct_explicit_na(niveled_psh, "inimputable"),
         nivel_ed = fct_collapse(nivel_ed, !!!reco$nivel_ed), 
# Grupos de edad
         edad = cut(v108, 
                    breaks = c(-Inf, 40, 50, 65, Inf), 
                    labels = c("30-40 años", "41-50 años", "51-65", "65 o más" ))) %>%  
  rename("Nivel educativo\ndel PSH" = niveled_psh, 
         "Nivel educativo\nde la persona" = nivel_ed) %>% 
# Filtrar eliminando las categorías con poca información
  filter_all(all_vars(!. %in% c("otro", "sin_información", "inimputable"))) %>%
#Preparar los datos para el gráfico  
  gather_set_data(c(1:2)) %>% 
# Reordenar el factor para que los ejes en el gráfico tengan este órden el eje x
  mutate(x = factor(x, levels = c("Nivel educativo\ndel PSH", "Nivel educativo\nde la persona"))) %>% 
  ggplot(aes(x, id = id, split = y, value = 1))  +
    geom_parallel_sets(aes(fill = `Nivel educativo\nde la persona`), show.legend = FALSE, alpha = 0.3) +
    geom_parallel_sets_axes(axis.width = 0.1, color = "lightgrey", fill = "white") +
    geom_parallel_sets_labels(angle = 0) + 
    scale_x_discrete(expand = c(0.08, 0.08)) + 
    facet_wrap(~edad, scales = "free") + 
    theme_minimal() +
    theme(axis.text.y = element_blank()) + 
    labs(title = "Movilidad educativa intergeneracional en Argentina", 
         subtitle = "Por grupos de edad a 2015", 
         caption = "n = 13912. Mayores de 30 años con información completa sobre nivel educativo propio y del PSH
         Elaboración propia con datos de la ENES-PISAC", 
         x = NULL)


  1. Aplica ponderador muestral

  2. Aplica ponderador muestral

  3. Aplica ponderador muestral