1. Descarga de datos

En este segundo encuentro trabajaremos con la base de datos de la Encuesta Anual de Hogares realizada en el 2019 por la Direccion General de Estadisticas y Censos. La descargaremos de aquí: https://data.buenosaires.gob.ar/dataset/encuesta-anual-hogares

eah <- read.csv("https://cdn.buenosaires.gob.ar/datosabiertos/datasets/direccion-general-de-estadisticas-y-censos/encuesta-anual-hogares/encuesta-anual-hogares-2019.csv", check.names = FALSE, encoding = "latin1")

2. Encoding

Cuando trabajamos con archivos cuyos códigos y/o referencias fueron escritas en el castellano y son levantados con softwares que no los reconocen pueden romperse esos caracteres y que nos devuelvan símbolos incoherentes. Por ejemplo, en el inglés no existen algunos caracteres que sí en el castellano. Por eso, puede ocurrir que se levante una base a la que R no sepa que codificación darle. Para eso esta el “encoding.” Para codificar aquellos caracteres de valores de acuerdo a nuestro parámetro elegido. La mas común en el castellano y sugerimos trabajar con latin1

https://es.wikipedia.org/wiki/ISO/IEC_8859-1

Para definir la codificacion por defecto en latin1 en R:

Tools <- Global Optiones <- Code <- Saving y elegir la opcion que prefieran

En el caso de que quieran abrir un script, que saben que tiene caracteres que pueden generar problemas:

File <- Reopen with encoding

3. Funciones de condición

Retomando el trabajo en la clase pasada, ahora trabajaremos con funciones de condición. Supongamos que queremos seleccionar de nuestra base aquellos registros que cumplen X condición. Para ello complementamos funciones como ifelse() y los operadores lógicos que vimos en la Clase I.

Supongamos que con la base descargada queremos asignar valores binarios, 1 y 2 , a una condición. Para ello podemos crear una nueva columna con el operador $ y definimos el valor 1 para mujeres y 2 para hombres

ifelse(condición, valor si se dá aquella condición, valor si no se da)

Ahora, supongamos que queremos trabajar con valores numericos y con varias condiciones. Para eso podemos incorporar un ifelse agrupado. ¿Qué podríamos hacer para conocer la clase a la que pertenecen?

typeof(eah$edad)
## [1] "integer"
eah$segmento_poblacion <-  ifelse(eah$edad < 11, "niñes",
                                       ifelse(eah$edad >=11 & eah$edad <= 18, "adolescentes",
                                              ifelse(eah$edad >=18 & eah$edad <=60, "adultes","ancianes")))
eah[1:10,c("edad","segmento_poblacion")]
##    edad segmento_poblacion
## 1    18       adolescentes
## 2    18       adolescentes
## 3    18       adolescentes
## 4    50            adultes
## 5    17       adolescentes
## 6    18       adolescentes
## 7    21            adultes
## 8     1              niñes
## 9    19            adultes
## 10   15       adolescentes

Aquí le estamos pidiendo que cree una nueva variable y cuyos valores estén definidos a partir de tres condiciones.

La primera, que todxs aquellos residentes del hogar que sean menores de 11 sean se le asigne el valor de “niñes”, la segunda, que aquellas personas entre 11 y 18, sean “adolescentes, entre 18 y 60 adultes y que el resto de los registros que se les asigne”ancianes”.

También podríamos utilizar la funcion with() que nos ahorra evocar nuestra objeto (base eah) todo el tiempo

¡Desafío!

Les proponemos que segun la base:

  1. Crear una campo cuyos valores asignen un identificador de 1 a los registros del campo dominio cuyos valores sean “Villas de Emergencia” y un 2 a aquellos cuyo registro es “Resto de la Ciudad”

  2. Crear otro campo cuyos valores asignen un identificador de 1 cuando el estado ocupacional es Ocupado, un 2 cuando es Desocupado y un 3 cuando es Inactivo

4. Concatenador pipe |>

Este último punto nos da el pie para hablar sobre el concatenador pipe.

Volvamos a nuestra tabla del comienzo. Supongamos que queremos hacerle varias consultas a nuestra base de datos de la Encuesta Permanente de Hogares. Pero que no queremos que cada vez que manipulamos la base de acuerdo a x criterio debamos crear un objeto sobre el cual realizarle una nueva consulta. En este caso nos piden el registro de todos aquellos varones de las Comunas 1 y 8, que sean jefes de hogares y que perciban un salario mayor o igual al promedio de los ingresos totales laborales, a esto le sumamos dos campos nuevos; uno con el cálculo del promedio del ingreso per capita familiar y el otro con la cantidad total de varones.

# Primero averiguamos los nombres de los campos
names(eah)
##  [1] "id"                          "nhogar"                     
##  [3] "miembro"                     "comuna"                     
##  [5] "dominio"                     "edad"                       
##  [7] "sexo"                        "parentesco_jefe"            
##  [9] "situacion_conyugal"          "num_miembro_padre"          
## [11] "num_miembro_madre"           "estado_ocupacional"         
## [13] "cat_ocupacional"             "calidad_ingresos_lab"       
## [15] "ingreso_total_lab"           "calidad_ingresos_no_lab"    
## [17] "ingreso_total_no_lab"        "calidad_ingresos_totales"   
## [19] "ingresos_totales"            "calidad_ingresos_familiares"
## [21] "ingresos_familiares"         "ingreso_per_capita_familiar"
## [23] "estado_educativo"            "sector_educativo"           
## [25] "nivel_actual"                "nivel_max_educativo"        
## [27] "años_escolaridad"            "lugar_nacimiento"           
## [29] "afiliacion_salud"            "hijos_nacidos_vivos"        
## [31] "cantidad_hijos_nac_vivos"    "segmento_poblacion"
# Despues vemos los valores del campo sexo
unique(eah$sexo)
## [1] "Mujer" "Varon"
# Hacemos la consulta:
consulta1 <- eah[eah$comuna %in% c(1,8) & eah$sexo == "Varon" & 
                eah$parentesco_jefe=="Jefe" & 
                 eah$ingreso_total_lab >= mean(eah$ingreso_total_lab),]  

promedio_per_capita <- mean(eah$ingreso_per_capita_familiar)

ctotal_varones_c1y8 <- nrow(eah[eah$comuna %in% c(1,8) & eah$sexo == "Varon",])

consulta1 <- cbind(consulta1, promedio_per_capita, ctotal_varones_c1y8)


# En orden: Le pedimos que inspeccione en todas las filas aquellos registros que aparecen en los campos: 
# Comuna los registros 1 y 8
# Sexo, los registros "Varon"
# Parentesco_jefe, los registros "Jefe"
# Ingreso_total_lab, aquellos ingresos laborales mayores o menores al promedio
# Por último, le pedimos todas las columnas al definir: ,]

# Luego creamos dos objetos que son:
# Promedio del Ingreso per capita familiar 
# Cantidad total de varones en las comunas 1 y 8 

# De esta manera estamos creando 3 objetos:
# 1) Consulta1,
# 2) Promedio_per_capita
# 3) ctotal_varones_c1y8
# 4) Que luego debemos indexarlos con cbind().

Pero esto implico haber creado un objeto, y solo para hacerle una consulta estadistica. Supongamos que queremos capitalizar la cantidad de objetos en el entorno, y con eso en la memoria, ¿qué pasa si podemos ahorrarnos crearlo y solo consultar?

eah[eah$comuna %in% c(1,8) & eah$sexo == "Varon" & 
      eah$parentesco_jefe=="Jefe" &
      eah$ingreso_total_lab >= mean(eah$ingreso_total_lab),] |> 
  cbind(promedio_per_capita=mean(eah$ingreso_per_capita_familiar),
        ctotal_varones_c1y8=nrow(eah[eah$comuna %in% c(1,8) & eah$sexo == "Varon",]))  |> 
  summary()
##        id           nhogar         miembro      comuna        dominio         
##  Min.   :  18   Min.   :1.000   Min.   :1   Min.   :1.000   Length:259        
##  1st Qu.:1124   1st Qu.:1.000   1st Qu.:1   1st Qu.:1.000   Class :character  
##  Median :2101   Median :1.000   Median :1   Median :1.000   Mode  :character  
##  Mean   :2158   Mean   :1.019   Mean   :1   Mean   :4.135                     
##  3rd Qu.:3140   3rd Qu.:1.000   3rd Qu.:1   3rd Qu.:8.000                     
##  Max.   :5353   Max.   :3.000   Max.   :1   Max.   :8.000                     
##       edad           sexo           parentesco_jefe    situacion_conyugal
##  Min.   :19.00   Length:259         Length:259         Length:259        
##  1st Qu.:35.00   Class :character   Class :character   Class :character  
##  Median :44.00   Mode  :character   Mode  :character   Mode  :character  
##  Mean   :44.56                                                           
##  3rd Qu.:54.00                                                           
##  Max.   :79.00                                                           
##  num_miembro_padre  num_miembro_madre  estado_ocupacional cat_ocupacional   
##  Length:259         Length:259         Length:259         Length:259        
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##  calidad_ingresos_lab ingreso_total_lab calidad_ingresos_no_lab
##  Length:259           Min.   : 21000    Length:259             
##  Class :character     1st Qu.: 29650    Class :character       
##  Mode  :character     Median : 37000    Mode  :character       
##                       Mean   : 48350                           
##                       3rd Qu.: 50000                           
##                       Max.   :200000                           
##  ingreso_total_no_lab calidad_ingresos_totales ingresos_totales
##  Min.   :     0       Length:259               Min.   : 21000  
##  1st Qu.:     0       Class :character         1st Qu.: 30000  
##  Median :     0       Mode  :character         Median : 38000  
##  Mean   :  4761                                Mean   : 53112  
##  3rd Qu.:     0                                3rd Qu.: 56800  
##  Max.   :150000                                Max.   :277000  
##  calidad_ingresos_familiares ingresos_familiares ingreso_per_capita_familiar
##  Length:259                  Min.   : 21000      Min.   :  3750             
##  Class :character            1st Qu.: 40000      1st Qu.: 13333             
##  Mode  :character            Median : 58000      Median : 25000             
##                              Mean   : 75299      Mean   : 32450             
##                              3rd Qu.: 87760      3rd Qu.: 41917             
##                              Max.   :335000      Max.   :185000             
##  estado_educativo   sector_educativo   nivel_actual       nivel_max_educativo
##  Length:259         Length:259         Length:259         Length:259         
##  Class :character   Class :character   Class :character   Class :character   
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character   
##                                                                              
##                                                                              
##                                                                              
##  años_escolaridad   lugar_nacimiento   afiliacion_salud   hijos_nacidos_vivos
##  Length:259         Length:259         Length:259         Length:259         
##  Class :character   Class :character   Class :character   Class :character   
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character   
##                                                                              
##                                                                              
##                                                                              
##  cantidad_hijos_nac_vivos segmento_poblacion promedio_per_capita
##  Length:259               Length:259         Min.   :26192      
##  Class :character         Class :character   1st Qu.:26192      
##  Mode  :character         Mode  :character   Median :26192      
##                                              Mean   :26192      
##                                              3rd Qu.:26192      
##                                              Max.   :26192      
##  ctotal_varones_c1y8
##  Min.   :1365       
##  1st Qu.:1365       
##  Median :1365       
##  Mean   :1365       
##  3rd Qu.:1365       
##  Max.   :1365

Veamos otros ejemplo de las ventajas del pipe.

# Supongamos que queremos: 
# 1) Conocer el nombre de las columnas
colnames(consulta1)
# 2) Hacer un informe de los nombres de estas
summary(colnames(consulta1))
# 3) Que solo nos devuelva los primeros dos informes
head(summary(colnames(consulta1)),n =2)

# Finalmente vemos que el codigo puede ser algo dificultoso de interpretarse a primera vista: 
# Para eso esta el pipe:

consulta1 |> 
  colnames() |> 
  summary() |> 
  head(n=2)

# No solo que que nos ahorra una sola linea de codigo dificil de interpretar a priemra vista, sino que tambien nos ahorra la construccion permanente de objetos
consulta2 <- consulta1
consulta3 <- colnames(consulta2)
consulta4 <- summary(consulta3)
consulta5 <- head(consulta4, n=2)

# El operador del paquete magrittr es igual de util para esto. Para ello hay que activar el paquete Tidyverse

# consulta1 %>%
#  colnames() %>% 
#  summary() %>%
#  head(n=2)

5. Tidyverse

¿Qué les parece si nos introducimos al paquete tidyverse?

El blog con la información de todos los paquetes: https://www.tidyverse.org/

La propuesta de trabajo de H. Wickham y G. Grolemund: https://r4ds.had.co.nz/introduction.html

Como verán, no es una biblioteca única, sino un conjunto de ellas que comparten una filosofía de diseño, gramática y estructura de datos; estos son tidyr, dplyr, ggplot2, tibble, readrr, y algunas más que extienden las capacidades de R base. Este último punto es importante, ya que en R es se puede llegar a los mismos resultados solo que por caminos distintos, solo que hay algunos que son más rápidos, intuitivos o incluso más largos también.

Pasemos a instalar el paquete:

# install.packages("tidyverse")
library(tidyverse)

5.1 Select

#Podemos elegir las columnas por su nombre o ubicacion.
names(eah)

# Supongamos que nos interesan los campos desde el 1 hasta el 8, el 15 y el 22. Primero llamemos a los campos por su nombre, y luego por su ubicación

select(.data = eah, 
       id,nhogar,miembro,comuna,dominio,edad,sexo,parentesco_jefe, ingreso_total_lab, ingreso_per_capita_familiar)  

select(.data = eah,
       1:8,15,22) # es mucho mas corto la linea de codigo escrita

# Y si usamos el pipe |> ?

eah |> 
  select(1:8,15,22)

# Quizas nos interesan solo las primeras 8

eah |> 
  select(-9:-31) |>
  colnames()

# O solo las que comienzan con "i", por ingresos

eah |> 
  select(starts_with("i"))

# O solo las que terminan con "s"

eah |> 
  select(ends_with("s"))

# O que contienen algun caracter

eah |> 
  select(contains("ingresos"))

5.2 Filter

# Como lo indica su nombre, nos permite filtrar registros segun condiciones
eah |> 
  filter(lugar_nacimiento=="CABA")

# Una o mas condiciones
eah |> 
  filter(sexo=="Mujer" & lugar_nacimiento=="CABA")

# Y si solo queremos ver las dos columnas referidas
eah |> 
  filter(sexo=="Mujer" & lugar_nacimiento=="CABA") |> 
  select(sexo, lugar_nacimiento)

# Si queremos ver aquellos registros que cuyo estado ocupacional sea "inactivo" o "desocupado", y que sean unicamente personas solteras
unique(eah$estado_ocupacional)

eah |> 
  filter(estado_ocupacional %in% c("Inactivo", "Desocupado") & situacion_conyugal=="Soltero/a") |> 
  select(estado_ocupacional, situacion_conyugal)

5.3 Mutate

# Con esta funcion podemos crear campos nuevos, o modificar los existentes. Es similar a lo que veiamos con el concatenador de $ 
# Aqui le estamos pidiendo una tabla con los registros de todas las mujeres, segun parentesco con jefa/e de hogar, y estamos creando un nuevo campo con los valores de su edad promedio 
eah |> 
  filter(sexo=="Mujer") |> 
  select(edad,sexo,parentesco_jefe) |> 
  mutate(promedio=mean(edad))

# Segun donde coloquemos las categorias, seran plasmadas en el dataset

eah |> 
  filter(sexo=="Mujer") |> 
  select(edad,sexo,parentesco_jefe) |> 
  mutate(promedio=mean(edad)) |> 
  select(sexo,edad,promedio, parentesco_jefe)

# Sin embargo tal vez la creacion aun no tiene suficiente impacto. Probemos con un ifelse
# A todas las mujeres jefas de hogar le asignaremos un 1
# A conyugue o pareja un 2
# Al resto un 3

eah |> 
  filter(sexo=="Mujer") |> 
  select(edad,sexo,parentesco_jefe) |> 
  mutate(nueva_categoria=ifelse(parentesco_jefe=="Jefe",1,
                                ifelse(parentesco_jefe=="Conyugue o pareja",2,3)))

# Asimismo podemos recodificar variables existentes

eah |> 
  filter(sexo=="Mujer") |> 
  select(edad,sexo,parentesco_jefe) |> 
  mutate(parentesco_jefe=ifelse(parentesco_jefe=="Jefe",1,
                                ifelse(parentesco_jefe=="Conyugue o pareja",2,3)))

# Tambien lo podemos hacer con las funciones de dplyr. Como el caso de case_when
# Nota. La virguilla se puede hacer con ALTGr (+ *)  sino Alt + 126
unique(eah$parentesco_jefe)

eah |> 
  filter(sexo=="Mujer") |> 
  select(edad,sexo,parentesco_jefe) |> 
  mutate(nueva_categoria=case_when(parentesco_jefe=="Jefe"~1,
                                   parentesco_jefe=="Conyugue o pareja"~2,
                                   TRUE~3))

# case_when(condicion a chequear ~ valor que sale si la condicion es cierta,
#          TRUE ~ valor a salir si la condicion no es cierta

5.4 Summarise

# Esta funcion permite hacer un resumen del DF completo y lo resume en una sola fila

eah |> 
  summarise(promedio=mean(edad)) # el nombre con el que sale la columna lo elegimos nosotres

eah |> 
  summarise(ingresos_promedio = mean(ingresos_totales))

# Tambien podemos saber valores maximos, minimos, mediana, media, y desvio

eah |> 
  summarise(minimo_ingeso=min(ingresos_totales),
            maximo_ingreso=max(ingresos_totales),
            media_ingreso=mean(ingresos_totales),
            mediana_ingreso=median(ingresos_totales),
            desvio_ingreso=sd(ingresos_totales),
            coeficiente_variacion_ingreso= (desvio_ingreso / mediana_ingreso)*100)

# Supongamos que queremos conocer la tasa de desocupados

¡Desafío!

Ahora que tenemos algunas herramientas para explorar tablas, identificar variables y manipular los datos les proponemos:

  1. Aplicar funciones de exploración de la base de datos EAH; cuántos campos y filas tiene, qué tipo de vectores son aquellos que son de las categorías de su interés, corroborar si el vector del campo ID es numérico, o no.

  2. Filtrar aquellos registros que nos interesan únicamente como mujeres jefas de hogares en Resto de la Ciudad y los ingresos totales generados.

  3. Luego del primer filtro, indagar cuántos casos hay, ¿qué funciones se les ocurre para conocer la cantidad de filas?

  4. Seleccionar únicamente los campos de interés.

  5. Crear un objeto que plasme los valores máximos, minimos, promedio, desvio de los ingresos de ingresos totales de la tabla en cuestión.