¡Hola! En este tercer encuentro profundizaremos en el paquete tidyverse a partir de funciones de agrupamiento, pivoteo de las tablas y representación gráfica de los datos. Continuaremos trabajando con la base de datos de la AUH.

1. Descarga de datos

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

Ahora activemos nuestra libreria

library(tidyverse)

2. Group by

Asi como en el encuentro pasado vimos algunas funciones de tabulado para seleccionar, filtrar, crear y/o modficiar segun algunos criterios, ahora veremos como agrupar nuestra informacion segun el criterio que establezcamos Supongamos que queremos pedirle a R una tabla que contenga la cantidad de registros acumulado de varones y mujeres por comuna.

eah |> 
  group_by(comuna) |> 
  summarise(cantidad=n())
## # A tibble: 15 × 2
##    comuna cantidad
##     <int>    <int>
##  1      1     1265
##  2      2      765
##  3      3      906
##  4      4     1300
##  5      5      818
##  6      6      755
##  7      7     1116
##  8      8     1640
##  9      9      967
## 10     10      765
## 11     11      728
## 12     12      801
## 13     13      833
## 14     14      847
## 15     15      813

Algunas cuestiones:

  1. Para que la tabla exprese los datos agrupados de acuerdo a x criterio debe ir acoplado con la función summarise(), que resume estadisticamente segun el criterio elegido. Como vimos en el encuentro pasado que con summarise podemos generar registros estadisticos a partir de la mediana, máximos, mínimos, desviación, etc. También podemos pedirle el numero de registros con la función n(), que nos devuelve el tamaño del grupo seleccionado, función que solo funciona dentro de otra función como summarise() o mutate()

  2. Veremos que nos devuelve dos columnas: Una, la columna con la variable que estamos trabajando y otra con los resultados del informe estadistico expresado en una nueva variable

  3. La tabla tiene 15 filas, ya que le pedimos que nos agrupe la información a partir de las categorías de la variable Comunas. Por ello que son 15 categorías únicas y excluyentes en las que se están agrupando los datos.

  4. Si corren la linea de código:

#?n()

Verán en el panel de salida la explicación de la función y a qué paquete pertenece.

Veamos qué sucede con con otras variables

unique(eah$parentesco_jefe)
## [1] "Jefe"                                "Otro no familiar"                   
## [3] "Padre/Madre/Suegro/a"                "Otro familiar"                      
## [5] "Conyugue o pareja"                   "Hijo/a - Hijastro/a"                
## [7] "Nieto/a"                             "Yerno/nuera"                        
## [9] "Servicio domestico y sus familiares"
eah |> 
  group_by(parentesco_jefe) |> 
  summarise(cantidad=n())
## # A tibble: 9 × 2
##   parentesco_jefe                     cantidad
##   <chr>                                  <int>
## 1 Conyugue o pareja                       2845
## 2 Hijo/a - Hijastro/a                     4526
## 3 Jefe                                    5848
## 4 Nieto/a                                  297
## 5 Otro familiar                            374
## 6 Otro no familiar                         135
## 7 Padre/Madre/Suegro/a                     194
## 8 Servicio domestico y sus familiares       39
## 9 Yerno/nuera                               61

En el primer encuentro vimos que con unique() pudimos apreciar la cantidad de categorias excluyentes que tienecada campo Y segun esa cantidad fueron agrupados los datos con group_by() y summarise().

Tambien podemos hacerlo con dos variables! Supongamos que queremos ver la cantidad de varones y mujeres por comuna

eah |> 
  group_by(comuna,sexo) |> 
  summarise(cantidad=n())
## # A tibble: 30 × 3
## # Groups:   comuna [15]
##    comuna sexo  cantidad
##     <int> <chr>    <int>
##  1      1 Mujer      683
##  2      1 Varon      582
##  3      2 Mujer      413
##  4      2 Varon      352
##  5      3 Mujer      503
##  6      3 Varon      403
##  7      4 Mujer      710
##  8      4 Varon      590
##  9      5 Mujer      463
## 10      5 Varon      355
## # … with 20 more rows

No es indiferente en el group_by() que variables elijamos primero, ya que su elección dependerá de donde aparezca y facilitarán o no su lectura. Aun así, podría ser mas fácil aun a la lectura, por que no armamos dos variables con la cantidad de mujeres y varones por comuna?

Desagreguemos la logica de la tabla;

Primero, pensemos qué tabla queremos que nos arroje. Para ello podemos seleccionar primero las dos columnas con las que queremos trabajar.

Segundo, sabemos que necesitamos crear dos objetos que resuman la cantidad de datos agrupados según un criterio; la cantidad de varones y mujeres por comuna. Entonces, agruparemos por comuna, pero le pediremos la sumatoria de casos que cumplan con una condición

eah |>
  group_by(comuna) |> 
  summarise(varones=sum(sexo=="Varon"),
            mujeres=sum(sexo=="Mujer"))
## # A tibble: 15 × 3
##    comuna varones mujeres
##     <int>   <int>   <int>
##  1      1     582     683
##  2      2     352     413
##  3      3     403     503
##  4      4     590     710
##  5      5     355     463
##  6      6     352     403
##  7      7     520     596
##  8      8     783     857
##  9      9     473     494
## 10     10     361     404
## 11     11     323     405
## 12     12     376     425
## 13     13     357     476
## 14     14     391     456
## 15     15     378     435

¡Otro más! ¿Y si queremos el promedio salarial de varones y mujeres por comuna que solo sean jefes de hogares, y por comuna?

resumen <- eah |> 
  filter(parentesco_jefe=="Jefe") |>
  group_by(comuna) |> 
  summarise(varones=sum(sexo=="Varon"),
            mujeres=sum(sexo=="Mujer"),
            promedio_v=round(mean(ingreso_total_lab[sexo == "Varon"])),
            promedio_m=round(mean(ingreso_total_lab[sexo=="Mujer"])))

Observen cómo el summarise es útil para pedir el resumen de:

  1. La suma de varones por comuna.

  2. La suma de mujeres por comuna.

  3. El promedio redondeando de los ingresos totales laborales en donde el jefe de hogar sea varon.

  4. El promedio redondeado de los ingresos laborales en donde la jefa del hogar sea mujer.

Una observación, ¿cómo sabe R que quiero el resultado promedio de los ingresos totales laborales separado por Varon y Mujer? Si no lo especificara, me arroja un resultado agrupado. Es por eso que dentro, del campo ingreso_total_lab abro [], para indagar dentro de la base y especificar la categoría con la que quiero que trabaje. Por último, la función round es para redondear valores con decimales…

3. Pivot Longer

Pasemos a pivotear los resultados. Pivot loger es una funcion útil cuando queremos pasar nuestras filas a columnas, pasando desde ancho a lo largo.

# pivot_longer(cols = el argumento cols nos está pidiendo que elijamos qué campos queremos pivotear,
#             names_to= "resumen" creamos un campo que se llame "resumen" y donde están agrupadas en forma de categorías los campos que señalamos arriba en cols= )
#             values_to ="valores")  creamos un campo que se llame "valores" y donde estarán las categorías de los campos que acabamos de pivotear. De esta manera nada se pierde, solo pivotean.

resumen |> 
  pivot_longer(cols=c(varones,mujeres,promedio_v,promedio_m), # tomamos estas columnas 
               names_to = "resumen", # los nombres de las columnas pasan a ser categorias de la nueva variable "resumen"
               values_to = "valores") |>  # los valores que refieren a ella pasan a ser parte de esta nueva variable. Entonces por comuna tenemos el resumen estadistico de cada uno
  filter(comuna %in% c(1,5)) |>  # traeme el resumen de las comunas 1 y 5
  view()

De esta manera tenemos los datos a lo largo antes que a lo ancho. En resumen estarán contenidas las categorías estadísticas y en valores, sus respectivos valores. De esta forma podemos trabajar solo con la comuna 1 y cada uno de los valores estadísticos en dos filas, antes que en 4. Esto también nos dará la ventaja de poder trabajarlo en un gráfico

Pivot Wider

Supongamos que queremos pivotear la tabla desde lo largo a lo ancho.

resumen2 <- eah |> 
  group_by(comuna,dominio) |> 
  summarise(promedio=mean(ingreso_per_capita_familiar))  
## `summarise()` has grouped output by 'comuna'. You can override using the
## `.groups` argument.
# Hasta aqui hemos agrupado el promedio de ingresos totales laborales segun comuna y el dominio


# La estructura de pivot_wider es así:

#pivot_wider(names_from = "dominio",  Le pedimos que pasen a ser campos/variables aquellas categorias del campo dominio
#    values_from = "promedio")  y que los datos de promedio pasen 

resumen2 |> 
  pivot_wider(names_from = "dominio",
    values_from = "promedio")
## # A tibble: 15 × 3
## # Groups:   comuna [15]
##    comuna `Resto de la Ciudad` `Villas de emergencia`
##     <int>                <dbl>                  <dbl>
##  1      1               29550.                  8104.
##  2      2               44995.                    NA 
##  3      3               24320.                    NA 
##  4      4               20729.                  7259.
##  5      5               28352.                    NA 
##  6      6               34113.                    NA 
##  7      7               25133.                  6208.
##  8      8               17290.                  7071.
##  9      9               19204.                  7433.
## 10     10               25983.                    NA 
## 11     11               27022.                    NA 
## 12     12               31003.                    NA 
## 13     13               38653.                    NA 
## 14     14               42670.                    NA 
## 15     15               29528.                  9032.

Notemos ahora cómo los datos pasaron de dos campos a tres. Sin embargo, notemos también como muchas filas tienen NAs. Si notamos la tabla sin pivotear, resumen2, no todas las categorías de dominio tienen su correlato con registros. Por ejemplo las comunas 2 y 3, no hay datos de los ingresos_per_capita_familiar en Villas de Emergencia. Ello conlleva a que los datos aparezcan sin registro.

¡Desafío!

  1. Inspeccionar la AUH y seleccionar aquellas variables con las que se quedarán para trabajar y construir con esta selección un nuevo objeto que se llame: “agrupado”

  2. Tomar una o dos categorías como máximo de una sola variable, e inspeccionar cuantos casos representa de la base. Para este caso no crearemos otro objeto.

  3. Con la variable que acabamos de trabajar, ahora agruparemos todos sus categorías para ver cuanto representa cada una. Para este caso deberán utilizar la funcion group_by() y summarise(). Elijan ustedes qué operación es la más convenientes; máximos, mínimos, promedio, etc.

  4. Inspeccionen el resumen realizado y pivoteen la base a lo largo o a lo ancho y reflexionen qué ventajas tiene hacerlo según el criterio elegido.

  5. A partir de la tabla generada, crear un nuevo objeto

5. Ggplot 2

Partiendo de que ggplot trabaja con de visualización, y los 3 componentes de la gramática; datos, objeto geometrico en cuestión y atributos:

ggplot(resumen)

Solo nos aparece un gráfico vacío, ya que no le estamos pidiendo qué tipo de objeto geométrico lo compondrá. Para ello debemos definirlo:

5.1 Histogramas

Partiendo de que un histograma es la distribución de frecuencias. Queremos conocer que valores de varones tienen mayor frecuencias

ggplot(resumen, # el data set
       mapping = aes(x=varones)) + # los atributos esteticos
  geom_histogram()  # el tipo de objeto geométrico
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# Supongamos que le queremos asignar un color
ggplot(resumen,
       aes(x=varones)) +
  geom_histogram(fill="red", # color de relleno
                 color="black", # color del contorno
                 alpha=.5)+ # transparencia
theme_bw() # Hay distintas tematicas para asignarles a los cuadros
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

5.2 Gráficos de densidad

ggplot(resumen,
       aes(x=varones)) +
geom_density(fill="#69b3a2", color="#e9ecef", alpha=0.8) + 
  theme_classic() # Podemos elegir distintas formas de presentar nuestras tablas con el grupo de funciones theme_

ggplot(resumen,
       aes(x=varones)) +
  geom_density(fill="#3A95B1", color="black", alpha=0.8) +
  theme_minimal() # algo más minimalista

5.3 Columnas

# Quiero conocer la cantidad de valores de varones por comuna
ggplot(resumen, aes(x=comuna,y=promedio_v)) +
  geom_col() 

# Supongamos que queremos asignarle un color a nuestra variable
# Por defecto, con la funcion fill(), si nuestros datos son de tipo numericos, asignarán un valor continuo de colores,
ggplot(resumen, aes(x=comuna,y=promedio_v,fill=promedio_v)) +
  geom_col() +
  coord_flip() # invertimos la perspectiva grafica

# Para una mejor visualización traemos la funcion reorder(x,y) que los ordenar de forma jerárquica
ggplot(resumen, aes(x=comuna,y=promedio_v,fill=promedio_v)) +
  geom_col(aes(x=reorder(comuna, promedio_v), y=promedio_v))+
  coord_flip() +
  theme_minimal()

# que nos cuenta el gráfico? que significan las categorías a la izquierda y las de debajo?

# Si pasamos nuestros datos a categoricos, desaparece la estetica de valores continuos, y aparece, por el contrario, 
# en formato categorico, unicos. 
ggplot(resumen, aes(x=comuna,y=promedio_v,fill=as.factor(promedio_v))) +
  geom_col() +
coord_flip()

5.4 Etiquetas

# Tambien pueden ser representados mediante etiquetas!
ggplot(resumen) + # en esta ocasion, estamos definiendo la estetica debajo
  geom_label(aes(x=comuna,y=promedio_v, label=comuna), color="white",fill="red")

5.5 Puntos

ggplot(resumen) +
  geom_point(aes(x=comuna,y=promedio_v,size=promedio_v)) # el parametro size asigna la estetica del punto segun el valor numerico más alto o bajo

# Podemos cambiarles las formas
ggplot(resumen) +
  geom_point(aes(x=comuna,y=promedio_v,size=promedio_v),shape=4,stroke=3) # Con shape cambiamos la forma de nuestros datos, con stroke asignamos mas o menos relleno

ggplot(resumen) +
geom_point(aes(x=comuna,y=promedio_v,size=promedio_v),
  color="black",
  fill="#69b3a2",
  shape=22,
  alpha=0.5,
  size=6,
  stroke = 1) +
  theme_linedraw()

ggplot(resumen) +
  geom_point(aes(x=comuna,y=promedio_v,size=promedio_v),
             color="orange",
             fill="#69b3a2",
             shape=21,
             alpha=0.5,
             size=6,
             stroke = 2) 

5.6 Tabla y Estética

Pero, ¿qué sería de la representación gráfica de las tablas sin un título correspondiente a sus datos?

ggplot(resumen, aes(x=comuna,y=promedio_v,fill=promedio_v)) +
  geom_col(aes(x=reorder(comuna, promedio_v), y=promedio_v), color="black")+
  coord_flip() +
  theme_minimal() +
  labs(title = "Promedio de ingreso laboral en varones jefes de hogares", # Titulo 
       subtitle = "Segun comuna", # Subitulo
       x="Comunas", # Eje X
       y="Promedio", # Eje Y
       fill="Promedio", # Panel izquierdo
       caption = "Elaboración Propia en base a la Encuesta Anual de Hogares") + # Referencia del grafico
  theme(plot.title=element_text(face="bold",              # Grosor del texto
                                size=16),                 # tamaño±o del texto
        plot.subtitle = element_text(face = "bold.italic", 
                                     size=13), 
        plot.caption = element_text(face="bold",          # Referencia del grafico 
                                    size=10,
                                    color="#44A75D"),    # Color
        axis.text = element_text(face = "bold",          # Categorias de ejes X-Y
                                 size = 10,
                                 colour = "red"),
        axis.title = element_text(face="bold",           # Titulo de categorias ejes X-Y
                                  size = 9,
                                  colour = "violet",
                                  hjust = 1),            # Posicion de las leyendas
        legend.title = element_text(face = "bold",
                                    size = 10,
                                    color="#D467CC"),    # Titulo de la leyenda 
        legend.text = element_text(face = "bold",
                                   size = 10,
                                   vjust = 1,
                                   color="#962445"))     # Datos de la leyenda 

¡Desafío!

Retomando aquél objeto que creamos en el desafío de este encuentro:

  1. Representar solo las frecuencias de sus variables mediante un histograma o gráfico de densidad y asignarle un título

  2. Representar mediante un cuadro de puntos dos variables, asignarle un título, un subtítulo, modificar el nombre de la leyenda a uno más pertinente y asignar una leyenda que describa quién lo hizo

  3. Representar mediante un cuadro de tablas dos variables,asignarle un título, un subtítulo, modificar el nombre de la leyenda a uno más pertinente, asignar una leyenda que describa quién lo hizo y modificar los atributos estéticos estos cuatro puntos.