Tidyverse

Este paquete agrupa una serie de paquetes que tienen una misma lógica en su diseño y por ende funcionan en armonía.

Entre ellos usaremos principalmente ggplot para realizar gráficos, y dplyr y tidyr para realizar transformaciones sobre nuestro set de datos.

A continuación cargamos la librería a nuestro ambiente. Para ello debe estar previamente instalada en nuestra pc.

library(tidyverse)
library(dplyr)
library(tidyr)
library(ggplot2)
library(lubridate)

Para mostrar el funcionamiento básico del tidyverse retomaremos el ejemplo de la clase 1, con lo cual volvemos a crear el set de datos del Indice de salarios.

INDICE  <- c(100,   100,   100,
             101.8, 101.2, 100.73,
             102.9, 102.4, 103.2)

FECHA  <-  c("Oct-16", "Oct-16", "Oct-16",
             "Nov-16", "Nov-16", "Nov-16",
             "Dec-16", "Dec-16", "Dec-16")


GRUPO  <-  c("Privado_Registrado","Público","Privado_No_Registrado",
             "Privado_Registrado","Público","Privado_No_Registrado",
             "Privado_Registrado","Público","Privado_No_Registrado")

Datos <- data.frame(INDICE, FECHA, GRUPO)

Dplyr

  • El paquete dplyr es definido por sus autores como una gramática para la manipulación de datos. De este modo sus funciones son conocidas como verbos.

  • El carácter principal para utilizar este paquete es %>% , pipe (de tubería).

  • El pipeline es un símbolo operatorio %>% que sirve para realizar varias operaciones de forma secuencial sin recurrir a paréntesis anidados o a sobrescribir múltiples bases de datos.

  • Los %>% toman el set de datos a su izquierda, y los transforman mediante los comandos a su derecha, en los cuales los elementos de la izquierda están implícitos. En otros términos.

  • \(f(x,y)\) es equivalente a \(x\) %>% \(f(.,y)\)

Veamos las principales funciones que pueden utilizarse con la lógica de este paquete:

glimpse

Permite ver la estructura de la tabla. Nos muestra:

  • número de filas
  • número de columnas
  • nombre de las columnas
  • tipo de dato de cada columna
  • las primeras observaciones de la tabla
glimpse(Datos)
## Rows: 9
## Columns: 3
## $ INDICE <dbl> 100.00, 100.00, 100.00, 101.80, 101.20, 100.73, 102.90, 102....
## $ FECHA  <chr> "Oct-16", "Oct-16", "Oct-16", "Nov-16", "Nov-16", "Nov-16", ...
## $ GRUPO  <chr> "Privado_Registrado", "Público", "Privado_No_Registrado", "P...

filter

Permite filtrar la tabla acorde al cumplimiento de condiciones lógicas

Datos %>% 
  filter(INDICE>101 , GRUPO == "Privado_Registrado")
##   INDICE  FECHA              GRUPO
## 1  101.8 Nov-16 Privado_Registrado
## 2  102.9 Dec-16 Privado_Registrado

Nótese que en este caso al separar con una (coma) , las condiciones se exige el cumplimiento de ambas. En caso de desear que se cumpla una sola condición debe utilizarse el caracter |

Datos %>% 
  filter(INDICE>101 | GRUPO == "Privado_Registrado")
##   INDICE  FECHA                 GRUPO
## 1  100.0 Oct-16    Privado_Registrado
## 2  101.8 Nov-16    Privado_Registrado
## 3  101.2 Nov-16               Público
## 4  102.9 Dec-16    Privado_Registrado
## 5  102.4 Dec-16               Público
## 6  103.2 Dec-16 Privado_No_Registrado

rename

Permite renombrar una columna de la tabla. Funciona de la siguiente manera: Data %>% rename( nuevo_nombre = viejo_nombre )

Datos %>% 
  rename(Periodo = FECHA)
##   INDICE Periodo                 GRUPO
## 1 100.00  Oct-16    Privado_Registrado
## 2 100.00  Oct-16               Público
## 3 100.00  Oct-16 Privado_No_Registrado
## 4 101.80  Nov-16    Privado_Registrado
## 5 101.20  Nov-16               Público
## 6 100.73  Nov-16 Privado_No_Registrado
## 7 102.90  Dec-16    Privado_Registrado
## 8 102.40  Dec-16               Público
## 9 103.20  Dec-16 Privado_No_Registrado

Nótese que a diferencia del ejemplo de la función filter donde utilizábamos == para comprobar una condición lógica, en este caso se utiliza sólo un = ya que lo estamos haciendo es asignar un nombre.

mutate

Permite agregar una variable a la tabla (especificando el nombre que tomará esta), que puede ser el resultado de operaciones sobre otras variables de la misma tabla.

En caso de especificar el nombre de una columna existente, el resultado de la operación realizada “sobrescribirá” la información de la columna con dicho nombre

Datos <- Datos %>% 
  mutate(Doble=INDICE*2)
Datos
##   INDICE  FECHA                 GRUPO  Doble
## 1 100.00 Oct-16    Privado_Registrado 200.00
## 2 100.00 Oct-16               Público 200.00
## 3 100.00 Oct-16 Privado_No_Registrado 200.00
## 4 101.80 Nov-16    Privado_Registrado 203.60
## 5 101.20 Nov-16               Público 202.40
## 6 100.73 Nov-16 Privado_No_Registrado 201.46
## 7 102.90 Dec-16    Privado_Registrado 205.80
## 8 102.40 Dec-16               Público 204.80
## 9 103.20 Dec-16 Privado_No_Registrado 206.40

case_when

Permite definir una variable, la cual toma un valor particular para cada condición establecida. Los valores asignados deben ser siempre del mismo tipo (numerico, caracter, logico,etc).

En caso de no cumplir ninguna de las condiciones establecidas la variable tomara valor NA

La sintaxis de la función es case_when( condicion lógica1 ~ valor asignado1).

Datos <- Datos %>% 
  mutate(Caso_cuando = case_when(GRUPO == "Privado_Registrado"   ~ INDICE*2,
                                 GRUPO == "Público"              ~ INDICE*3))
Datos
##   INDICE  FECHA                 GRUPO  Doble Caso_cuando
## 1 100.00 Oct-16    Privado_Registrado 200.00       200.0
## 2 100.00 Oct-16               Público 200.00       300.0
## 3 100.00 Oct-16 Privado_No_Registrado 200.00          NA
## 4 101.80 Nov-16    Privado_Registrado 203.60       203.6
## 5 101.20 Nov-16               Público 202.40       303.6
## 6 100.73 Nov-16 Privado_No_Registrado 201.46          NA
## 7 102.90 Dec-16    Privado_Registrado 205.80       205.8
## 8 102.40 Dec-16               Público 204.80       307.2
## 9 103.20 Dec-16 Privado_No_Registrado 206.40          NA

Una forma de manejar la asignación de valores faltantes es crear una “condición” que sea igual a TRUE. Esto funciona como la parte de else de una estructura condicional

Datos %>% 
  mutate(Caso_cuando = case_when(GRUPO == "Privado_Registrado"   ~ INDICE*2,
                                 GRUPO == "Público"              ~ INDICE*3,
                                 TRUE ~ 1000))
##   INDICE  FECHA                 GRUPO  Doble Caso_cuando
## 1 100.00 Oct-16    Privado_Registrado 200.00       200.0
## 2 100.00 Oct-16               Público 200.00       300.0
## 3 100.00 Oct-16 Privado_No_Registrado 200.00      1000.0
## 4 101.80 Nov-16    Privado_Registrado 203.60       203.6
## 5 101.20 Nov-16               Público 202.40       303.6
## 6 100.73 Nov-16 Privado_No_Registrado 201.46      1000.0
## 7 102.90 Dec-16    Privado_Registrado 205.80       205.8
## 8 102.40 Dec-16               Público 204.80       307.2
## 9 103.20 Dec-16 Privado_No_Registrado 206.40      1000.0

select

Permite especificar la serie de columnas que se desea conservar de un DataFrame. También pueden especificarse las columnas que se desean descartar (agregándoles un -). Muy útil para agilizar el trabajo en bases de datos de gran tamaño.

Datos2 <- Datos %>% 
  select(INDICE, FECHA, GRUPO)
Datos2
##   INDICE  FECHA                 GRUPO
## 1 100.00 Oct-16    Privado_Registrado
## 2 100.00 Oct-16               Público
## 3 100.00 Oct-16 Privado_No_Registrado
## 4 101.80 Nov-16    Privado_Registrado
## 5 101.20 Nov-16               Público
## 6 100.73 Nov-16 Privado_No_Registrado
## 7 102.90 Dec-16    Privado_Registrado
## 8 102.40 Dec-16               Público
## 9 103.20 Dec-16 Privado_No_Registrado
Datos <- Datos %>% 
  select(-c(Doble,Caso_cuando))
Datos
##   INDICE  FECHA                 GRUPO
## 1 100.00 Oct-16    Privado_Registrado
## 2 100.00 Oct-16               Público
## 3 100.00 Oct-16 Privado_No_Registrado
## 4 101.80 Nov-16    Privado_Registrado
## 5 101.20 Nov-16               Público
## 6 100.73 Nov-16 Privado_No_Registrado
## 7 102.90 Dec-16    Privado_Registrado
## 8 102.40 Dec-16               Público
## 9 103.20 Dec-16 Privado_No_Registrado

arrange

Permite ordenar la tabla por los valores de determinada/s variable/s. Es útil cuando luego deben hacerse otras operaciones que requieran del ordenamiento de la tabla

Datos <- Datos %>% 
  arrange(GRUPO, INDICE)
Datos
##   INDICE  FECHA                 GRUPO
## 1 100.00 Oct-16 Privado_No_Registrado
## 2 100.73 Nov-16 Privado_No_Registrado
## 3 103.20 Dec-16 Privado_No_Registrado
## 4 100.00 Oct-16    Privado_Registrado
## 5 101.80 Nov-16    Privado_Registrado
## 6 102.90 Dec-16    Privado_Registrado
## 7 100.00 Oct-16               Público
## 8 101.20 Nov-16               Público
## 9 102.40 Dec-16               Público

summarise

Crea una nueva tabla que resuma la información original. Para ello, definimos las variables de resumen y las formas de agregación.

Datos %>% 
  summarise(Indprom = mean(INDICE))
##    Indprom
## 1 101.3589

group_by

Esta función permite realizar operaciones de forma agrupada. Lo que hace la función es “separar” a la tabla según los valores de la variable indicada y realizar las operaciones que se especifican a continuación, de manera independiente para cada una de las “subtablas”. En nuestro ejemplo, sería útil para calcular el promedio de los indices por Fecha

Datos %>% 
  group_by(FECHA) %>%
  summarise(Indprom = mean(INDICE))
## # A tibble: 3 x 2
##   FECHA  Indprom
##   <chr>    <dbl>
## 1 Dec-16    103.
## 2 Nov-16    101.
## 3 Oct-16    100

Joins

Otra implementación muy importante del paquete dplyr son las funciones para unir tablas (joins)

left_join

Veamos un ejemplo de la función left_join (una de las más utilizadas en la práctica).
Para ello crearemos previamente un Dataframe que contenga un Ponderador para cada uno de los Grupos del Dataframe Datos. Aprovecharemos el ejemplo para introducir la función weigthed.mean, y así calcular un Indice Ponderado.

Ponderadores <- data.frame(GRUPO = c("Privado_Registrado","Público","Privado_No_Registrado"),
                            PONDERADOR = c(50.16,29.91,19.93))

Datos_join <- Datos %>% 
  left_join(.,Ponderadores, by = "GRUPO")
Datos_join
##   INDICE  FECHA                 GRUPO PONDERADOR
## 1 100.00 Oct-16 Privado_No_Registrado      19.93
## 2 100.73 Nov-16 Privado_No_Registrado      19.93
## 3 103.20 Dec-16 Privado_No_Registrado      19.93
## 4 100.00 Oct-16    Privado_Registrado      50.16
## 5 101.80 Nov-16    Privado_Registrado      50.16
## 6 102.90 Dec-16    Privado_Registrado      50.16
## 7 100.00 Oct-16               Público      29.91
## 8 101.20 Nov-16               Público      29.91
## 9 102.40 Dec-16               Público      29.91
Datos_Indice_Gral <- Datos_join %>% 
  group_by(FECHA) %>% 
  summarise(Indice_Gral = weighted.mean(INDICE,w = PONDERADOR))

Datos_Indice_Gral
## # A tibble: 3 x 2
##   FECHA  Indice_Gral
##   <chr>        <dbl>
## 1 Dec-16        103.
## 2 Nov-16        101.
## 3 Oct-16        100

Tidyr

El paquete tidyr esta pensado para facilitar el emprolijamiento de los datos.

Gather es una función que nos permite pasar los datos de forma horizontal a una forma vertical.

spread es una función que nos permite pasar los datos de forma vertical a una forma horizontal.

#Utilzamos un conjunto de datos que viene con la librería datasets
library(datasets)

data(iris)
iris <- iris %>% 
  mutate(id = 1:nrow(.)) %>%  #le agrego un ID
  select(id, everything()) # lo acomodo para que el id este primero. 

head(iris)
##   id Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1  1          5.1         3.5          1.4         0.2  setosa
## 2  2          4.9         3.0          1.4         0.2  setosa
## 3  3          4.7         3.2          1.3         0.2  setosa
## 4  4          4.6         3.1          1.5         0.2  setosa
## 5  5          5.0         3.6          1.4         0.2  setosa
## 6  6          5.4         3.9          1.7         0.4  setosa

Gather y Spread

iris_vertical <- iris %>% gather(., # el . llama a lo que esta atras del %>% 
                                 key   = Variables,
                                 value = Valores,
                                 2:5) #le indico que columnas juntar
head(iris_vertical)
##   id Species    Variables Valores
## 1  1  setosa Sepal.Length     5.1
## 2  2  setosa Sepal.Length     4.9
## 3  3  setosa Sepal.Length     4.7
## 4  4  setosa Sepal.Length     4.6
## 5  5  setosa Sepal.Length     5.0
## 6  6  setosa Sepal.Length     5.4

Podemos deshacer el gather con un Spread

iris_horizontal <- iris_vertical %>%
  spread(. ,
         key   = Variables, #la llave es la variable que va a dar los nombres de columna
         value = Valores) #los valores con que se llenan las celdas
head(iris_horizontal)
##   id Species Petal.Length Petal.Width Sepal.Length Sepal.Width
## 1  1  setosa          1.4         0.2          5.1         3.5
## 2  2  setosa          1.4         0.2          4.9         3.0
## 3  3  setosa          1.3         0.2          4.7         3.2
## 4  4  setosa          1.5         0.2          4.6         3.1
## 5  5  setosa          1.4         0.2          5.0         3.6
## 6  6  setosa          1.7         0.4          5.4         3.9

Lubridate

El paquete lubridate está pensado para trabajar con los datos tipo fecha(date) o fecha-hora(datetime) para cambiarles el formato, realizar operaciones y extraer información

Cambio de formato

Existe una gran cantidad de funciones para realizar esto. La idea general es poder llevar los objetos datetime a un formato común compuesto de los elementos: año, mes, día, hora, minuto y segundo (también se puede setear el huso horario)

fecha  <- "04/12/92 17:35:16"
fecha
## [1] "04/12/92 17:35:16"

Con la función dmy_hms podemos convertir este string a una fecha: estamos indicando que el formato de la fecha es día(d), mes(m), año(y), hora(h), minuto(m) y segundo(s)

fecha  <- dmy_hms(fecha)
fecha
## [1] "1992-12-04 17:35:16 UTC"

Muchas funciones de lubridate operan con esta misma lógica

Otra función para realizar un cambio de formato es parse_date_time. Permite construir objetos datetime a partir de datos más complejos, como por ejemplo cuando aparece el nombre del mes y el año.

En el parámetro x pasamos el dato de la fecha y en el parámetro orders especificamos el orden en el cual se encuentra la información de la fecha

fecha2  <- "Dec-92"
fecha2 <- parse_date_time(fecha2, orders = 'my')
fecha2
## [1] "1992-12-01 UTC"

Extracción de información

Existen muchas funciones muy sencillas para extraer información de un objeto datetime. Algunas son

year(fecha) # Obtener el año
## [1] 1992
month(fecha) #Obtener el mes
## [1] 12
day(fecha) # Obtener el día
## [1] 4
wday(fecha, label = TRUE) #Obtener el nombre del día
## [1] vie\\.
## Levels: dom\\. < lun\\. < mar\\. < mié\\. < jue\\. < vie\\. < sáb\\.
hour(fecha) #Obtener la hora
## [1] 17

Operaciones

Podemos sumar o restarle cualquier período de tiempo a un objeto datetime

# Sumo dos días 
fecha + days(2)
## [1] "1992-12-06 17:35:16 UTC"
# Resto 1 semana y dos horas
fecha - (weeks(1) + hours(2))
## [1] "1992-11-27 15:35:16 UTC"

Ggplot2

ggplot tiene su sintaxis propia. La idea central es pensar los gráficos como una sucesión de capas, que se construyen una a la vez.

ggplot tiene muchos comandos, y no tiene sentido saberlos de memoria, es siempre útil reutilizar gráficos viejos y tener a mano el machete.

library(ggplot2)
library(ggthemes)  # estilos de gráficos
library(ggrepel)   # etiquetas de texto más prolijas que las de ggplot
library(scales)    # tiene la función 'percent()'
## 
## Attaching package: 'scales'
## The following object is masked from 'package:purrr':
## 
##     discard
## The following object is masked from 'package:readr':
## 
##     col_factor
ggplot(data = iris, aes(x = Petal.Length, Petal.Width, color = Species))+
  geom_point(alpha=0.75)+
  labs(title = "Medidas de los pétalos por especie")+
  theme(legend.position = 'none')+
  facet_wrap(~Species)

Capas del Gráfico

Veamos ahora, el “paso a paso” del armado del mismo.

En primera instancia solo defino los ejes. Y en este caso un color particular para cada Especie.

g <- ggplot(data = iris, aes(x = Petal.Length, Petal.Width, color = Species))
g

Luego, defino el tipo de gráfico. El alpha me permite definir la intensidad de los puntos

g <- g +  geom_point(alpha=0.25)
g

Las siguientes tres capas me permiten respectivamente:

  • Definir el título del gráfico
  • Quitar la leyenda
  • Abrir el gráfico en tres fragmentos, uno para cada especie
g <- g +
  labs(title = "Medidas de los pétalos por especie")+
  theme(legend.position = 'none')+
  facet_wrap(~Species)
g

Extensiones de GGplot.

La librería GGplot tiene a su vez muchas otras librerías que extienden sus potencialidades. Entre nuestras favoritas están:

  • gganimate: Para hacer gráficos animados.
  • ggridge: Para hacer gráficos de densidad faceteados
  • ggally: Para hacer varios gráficos juntos.
library(GGally)

ggpairs(iris,  mapping = aes(color = Species))

library(ggridges)
## Warning: package 'ggridges' was built under R version 4.0.3
ggplot(iris, aes(x = Sepal.Length, y = Species, fill=Species)) + 
  geom_density_ridges()
## Picking joint bandwidth of 0.181

Lo útil de hacer gráficos en R, en lugar de por ejemplo excel, es que podemos hacer uso de más dimensiones, por ejemplo:

  • Gráficos que necesitan la información a nivel de microdatos. puntos, boxplots, Kernels, etc.
  • Abrir el mismo gráfico según alguna variable discreta: facet_wrap()
  • Parametrizar otras variables, para aumentar la dimensionalidad del gráficos.
    • color color =
    • rellenofill =
    • forma shape =
    • tamaño size =
    • transparencia alpha =

Esto permite tener, en el plano, gráficos de muchas dimensiones de análisis

Cuando queremos utilizar estos parámetros para representar una variable, los definimos dentro del aes(), aes(... color = ingresos), cuando queremos simplemente mejorar el diseño, se asignan por fuera, o dentro de cada tipo de gráficos, geom_col(color = 'green').

levanto una base de microdatos de EPH para graficar

Individual_t117 <- read.table(paste0("usu_individual_t117.txt"),
                              sep=";", dec=",", header = TRUE, fill = TRUE)

Boxplots

Hacemos un procesamiento simple: Sacamos los ingresos iguales a cero y las no respuestas de nivel educativo.
Las variables sexo( CH04 ) y Nivel educativo están codificadas como números, y el R las entiende como numéricas.

Es importante que las variables sean del tipo que conceptualmente les corresponde (el nivel educativo es una variable categórica, no continua), para que el ggplot pueda graficarlo correctamente.

ggdata <- Individual_t117 %>% 
  filter(P21>0, !is.na(NIVEL_ED)) %>% 
  mutate(NIVEL_ED = as.factor(NIVEL_ED),
         CH04     = as.factor(CH04))

Si queremos hacer un boxplot del ingreso para cada nivel educativo, asignamos esta variable a x, group y fill

ggplot(ggdata, aes(x = NIVEL_ED, y = P21, group = NIVEL_ED, fill = NIVEL_ED )) +
  geom_boxplot()+
  scale_y_continuous(limits = c(0, 40000))
## Warning: Removed 209 rows containing non-finite values (stat_boxplot).

Si queremos agregar la dimensión sexo, podemos hacer un facet_wrap()

ggplot(ggdata, aes(x= NIVEL_ED, y = P21, group = NIVEL_ED, fill = NIVEL_ED )) +
  geom_boxplot()+
  scale_y_continuous(limits = c(0, 40000))+
  facet_wrap(~ CH04, labeller = "label_both")
## Warning: Removed 209 rows containing non-finite values (stat_boxplot).

En este gráfico, el foco de atención sigue puesto en las diferencias de nivel educativo, pero neutralizamos el efecto de la variable sexo.

Si lo que queremos hacer es poner el foco de atención en las diferencias por sexo, neutralizamos el efecto del nivel educativo, facetiando por nivel educativo.

ggplot(ggdata, aes(x= CH04, y = P21, group = CH04, fill = CH04 )) +
  geom_boxplot()+
  scale_y_continuous(limits = c(0, 40000))+
  facet_wrap(~ NIVEL_ED, labeller = "label_both")
## Warning: Removed 209 rows containing non-finite values (stat_boxplot).

Kernels (OPCIONAL)

Podemos hacer una nueva versión del gráfico 2. Utilizando un procesamiento similar al que hicimos antes.

datagraf <-Individual_t117 %>% 
  select(REGION,P47T,T_VI, TOT_P12, P21 , PONDII, CH04) %>% 
  filter(!is.na(P47T), P47T > 0 ) %>% 
  mutate(REGION             = case_when(REGION == 1    ~ 'GBA',
                                        REGION == 40   ~ 'NOA',
                                        REGION == 41   ~ 'NEA',
                                        REGION == 42   ~ 'Cuyo',
                                        REGION == 43   ~ 'Pampeana',
                                        REGION == 44   ~ 'Patagonia',
                                        FALSE          ~ 'otro'),
         ingreso_laboral    = as.numeric(TOT_P12 + P21),
         ingreso_no_laboral = as.numeric(T_VI),
         CH04               = case_when(CH04 == 1 ~ "Varon",
                                        CH04 == 2 ~ "Mujer",
                                        FALSE     ~ "Otro") ) %>% 
  gather(., key = Tipo_ingreso, Ingreso, c((ncol(.)-1):ncol(.)))
head(datagraf) 
##     REGION  P47T  T_VI TOT_P12  P21 PONDII  CH04    Tipo_ingreso Ingreso
## 1 Pampeana  1000  1000       0    0   1088 Mujer ingreso_laboral       0
## 2 Pampeana  1500     0       0 1500   1386 Varon ingreso_laboral    1500
## 3 Pampeana  9500     0       0 9500   1130 Mujer ingreso_laboral    9500
## 4 Pampeana 10000 10000       0    0   1473 Varon ingreso_laboral       0
## 5 Pampeana  9000  9000       0    0   1644 Mujer ingreso_laboral       0
## 6 Pampeana  8000     0       0 8000   1629 Mujer ingreso_laboral    8000

Con los Kernels, no necesitamos dividir a la población en deciles, porque podemos tener una mirada completa de la forma de la distribución.

Para este gráfico, quiero eliminar los ingresos = 0

datagraf2 <- datagraf %>% filter( Ingreso !=0)
  
  
ggplot(datagraf2, aes(
  x = Ingreso,
  weights = PONDII,
  group = Tipo_ingreso,
  fill = Tipo_ingreso)) +
  geom_density(alpha=0.7,adjust =2)+
  labs(x="Distribución del ingreso", y="",
       title=" Total según tipo de ingreso y género", 
       caption = "Fuente: Encuesta Permanente de Hogares")+
  scale_x_continuous(limits = c(0,50000))+
  theme_tufte()+
  scale_fill_gdocs()+
  theme(legend.position = "bottom",
        plot.title      = element_text(size=12))+
  facet_wrap(~ CH04, scales = "free")
## Warning: Removed 179 rows containing non-finite values (stat_density).

ggsave(filename = paste0("Resultados", "Kernel_1.png"),scale = 2)
## Saving 14 x 10 in image
## Warning: Removed 179 rows containing non-finite values (stat_density).

En este tipo de gráficos, importa mucho qué variable se utiliza para facetear y qué variable para agrupar, ya que la construcción de la distribución es diferente.

ggplot(datagraf2, aes(
  x = Ingreso,
  weights = PONDII,
  group = CH04,
  fill = CH04)) +
  geom_density(alpha=0.7,adjust =2)+
  labs(x="Distribución del ingreso", y="",
       title=" Total según tipo de ingreso y género", 
       caption = "Fuente: Encuesta Permanente de Hogares")+
  scale_x_continuous(limits = c(0,50000))+
  theme_tufte()+
  scale_fill_gdocs()+
  theme(legend.position = "bottom",
        plot.title      = element_text(size=12))+
  facet_wrap(~Tipo_ingreso, scales = "free")
## Warning: Removed 179 rows containing non-finite values (stat_density).

ggsave(filename = paste0("Resultados", "Kernel_1.png"),scale = 2)
## Saving 14 x 10 in image
## Warning: Removed 179 rows containing non-finite values (stat_density).

El eje y no tiene demasiada interpretabilidad en los Kernel, porque hace a la forma en que se construyen las distribuciones.

Tendencia (OPCIONAL)

Para realizar estos gráficos, vamos a modificar un poco los datos:

  • filtramos los ingresos iguales a 0.
  • eliminamos las no respuestas de nivel educativo y las personas con educación especial.
  • eliminamos las respuestas de tipo de establecimiento = ‘otros’.
  • recodificamos las variables para que tengan nombres más sugestivos:
    • Nivel educativo además la convertimos a factor, porque queremos explicitarle el orden de los valores con levels(). El “\n”" es un caracter especial que permite que el string continúe en la siguiente línea.
    • Sexo.
    • Tipo de establecimiento.
ggdata <- Individual_t117 %>% 
  filter(P21>0,
         !is.na(NIVEL_ED),
         NIVEL_ED!=7, 
         PP04A !=3) %>% 
  mutate(NIVEL_ED = factor(case_when(NIVEL_ED == 1  ~ 'Primaria \n Incompleta', # '\n' significa carriage return, o enter
                                     NIVEL_ED == 2  ~ 'Primaria \n Completa',
                                     NIVEL_ED == 3  ~ 'Secundaria \nIncompleta',
                                     NIVEL_ED == 4  ~ 'Secundaria \nCompleta',
                                     NIVEL_ED == 5  ~ 'Superior \nUniversitaria \nIncompleta',
                                     NIVEL_ED == 6  ~ 'Superior \nUniversitaria \nCompleta',
                                     FALSE          ~ 'Otro'),
                           levels= c('Primaria \n Incompleta',
                                     'Primaria \n Completa',
                                     'Secundaria \nIncompleta',
                                     'Secundaria \nCompleta',
                                     'Superior \nUniversitaria \nIncompleta',
                                     'Superior \nUniversitaria \nCompleta')),
         Sexo     = case_when(CH04 == 1 ~ 'Varón',
                              CH04 == 2 ~ 'Mujer'),
         Establecimiento    = case_when(PP04A == 1 ~ 'Estatal',
                                        PP04A == 2 ~ 'Privado',
                                        FALSE      ~ 'Otro'))

head(ggdata)
##                          CODUSU ANO4 TRIMESTRE NRO_HOGAR COMPONENTE H15 REGION
## 1 TQRMNOQURHKOMLCDEFIAH00469284 2017         1         1         13   1     43
## 2 TQRMNORWSHLMLOCDEFIAH00497956 2017         1         1          1   1     43
## 3 TQRMNORRUHJLKUCDEFIAH00498010 2017         1         1          1   1     43
## 4 TQRMNORRUHJLKUCDEFIAH00498010 2017         1         1          2   1     43
## 5 TQRMNOQUSHJOMMCDEFIAH00498029 2017         1         1          1   1     43
## 6 TQRMNOQQWHLLKTCDEFIAH00497900 2017         1         1          1   1     43
##   MAS_500 AGLOMERADO PONDERA CH03 CH04       CH05 CH06 CH07 CH08 CH09 CH10 CH11
## 1       S          2     861    4    1 22/11/1996   20    1    4    1    2    0
## 2       S          2     514    1    2 07/07/1952   64    3    1    1    2    0
## 3       S          2     888    1    1 23/07/1986   30    5    1    1    1    1
## 4       S          2     888    8    2 02/02/1992   24    5    1    1    1    1
## 5       S          2     794    1    1 27/05/1974   42    1    4    1    2    0
## 6       S          2    1141    1    2 20/11/1957   59    5    4    1    2    0
##   CH12 CH13 CH14 CH15 CH15_COD CH16 CH16_COD
## 1    2    1   NA    1       NA    1       NA
## 2    4    1   NA    1       NA    1       NA
## 3    7    2    3    2       NA    2       NA
## 4    7    2    3    2       NA    2       NA
## 5    2    1   NA    4      221    1       NA
## 6    7    1   NA    1       NA    1       NA
##                                NIVEL_ED ESTADO CAT_OCUP CAT_INAC IMPUTA PP02C1
## 1                  Primaria \n Completa      1        3        0      0      0
## 2                 Secundaria \nCompleta      1        3        0      0      0
## 3 Superior \nUniversitaria \nIncompleta      1        3        0      0      0
## 4 Superior \nUniversitaria \nIncompleta      1        3        0      0      0
## 5                  Primaria \n Completa      1        2        0      0      0
## 6   Superior \nUniversitaria \nCompleta      1        3        0      0      0
##   PP02C2 PP02C3 PP02C4 PP02C5 PP02C6 PP02C7 PP02C8 PP02E PP02H PP02I PP03C
## 1      0      0      0      0      0      0      0     0     0     0     1
## 2      0      0      0      0      0      0      0     0     0     0     1
## 3      0      0      0      0      0      0      0     0     0     0     1
## 4      0      0      0      0      0      0      0     0     0     0     1
## 5      0      0      0      0      0      0      0     0     0     0     1
## 6      0      0      0      0      0      0      0     0     0     0     0
##   PP03D PP3E_TOT PP3F_TOT PP03G PP03H PP03I PP03J INTENSI PP04A PP04B_COD
## 1     0       48        0     2     0     2     1       3     2      5601
## 2     0       30        0     2     0     2     2       2     1        85
## 3     0       30        0     2     0     2     2       2     2      9301
## 4     0       24        0     1     1     1     2       1     2      4806
## 5     0       40        0     2     0     2     2       2     2      4000
## 6     0        0        0     2     0     2     2       4     2      6900
##   PP04B1 PP04B2 PP04B3_MES PP04B3_ANO PP04B3_DIA PP04C PP04C99 PP04D_COD PP04G
## 1      2      0          0          0          0     4       0     34314     4
## 2      2      0          0          0          0     7       0     10332     1
## 3      2      0          0          0          0     8       0     10333     1
## 4      2      0          0          0          0    99       2     30314     1
## 5      2      0          0          0          0     1       0     72113     8
## 6      2      0          0          0          0     3       0     11333     1
##   PP05B2_MES PP05B2_ANO PP05B2_DIA PP05C_1 PP05C_2 PP05C_3 PP05E PP05F PP05H
## 1          0          0          0       0       0       0     0     0     0
## 2          0          0          0       0       0       0     0     0     0
## 3          0          0          0       0       0       0     0     0     0
## 4          0          0          0       0       0       0     0     0     0
## 5          0          0          0       1       3       1     1     7     6
## 6          0          0          0       0       0       0     0     0     0
##   PP06A PP06C PP06D PP06E PP06H PP07A PP07C PP07D PP07E PP07F1 PP07F2 PP07F3
## 1     0     0     0     0     0     5     2     0     0      2      2      2
## 2     0     0     0     0     0     6     2     0     0      2      2      2
## 3     0     0     0     0     0     6     2     0     0      2      2      2
## 4     0     0     0     0     0     5     2     0     0      2      2      2
## 5     2  6000     0     0     0     0     0     0     0      0      0      0
## 6     0     0     0     0     0     5     2     0     0      2      2      2
##   PP07F4 PP07F5 PP07G1 PP07G2 PP07G3 PP07G4 PP07G_59 PP07H PP07I PP07J PP07K
## 1      2      5      2      2      2      2        5     2     2     1     4
## 2      2      5      1      1      1      1        0     1     0     1     1
## 3      2      5      2      1      1      1        0     1     0     1     1
## 4      2      5      1      1      1      1        0     1     0     1     1
## 5      0      0      0      0      0      0        0     0     0     0     0
## 6      2      5      1      1      1      2        0     2     2     1     4
##   PP08D1 PP08D4 PP08F1 PP08F2 PP08J1 PP08J2 PP08J3 PP09A PP09A_ESP PP09B PP09C
## 1   1500      0      0      0      0      0      0     0               0     0
## 2   9500      0      0      0      0      0      0     0               0     0
## 3   7000      0      0      0      0      0      0     0               0     0
## 4   8000      0      0      0      0      0      0     0               0     0
## 5      0      0      0      0      0      0      0     0               0     0
## 6  14000      0      0      0   7000      0      0     0               0     0
##   PP09C_ESP PP10A PP10C PP10D PP10E PP11A PP11B_COD PP11B1 PP11B2_MES
## 1              NA    NA    NA    NA    NA        NA     NA         NA
## 2              NA    NA    NA    NA    NA        NA     NA         NA
## 3              NA    NA    NA    NA    NA        NA     NA         NA
## 4              NA    NA    NA    NA    NA        NA     NA         NA
## 5              NA    NA    NA    NA    NA        NA     NA         NA
## 6              NA    NA    NA    NA    NA        NA     NA         NA
##   PP11B2_ANO PP11B2_DIA PP11C PP11C99 PP11D_COD PP11G_ANO PP11G_MES PP11G_DIA
## 1         NA         NA    NA      NA        NA        NA        NA        NA
## 2         NA         NA    NA      NA        NA        NA        NA        NA
## 3         NA         NA    NA      NA        NA        NA        NA        NA
## 4         NA         NA    NA      NA        NA        NA        NA        NA
## 5         NA         NA    NA      NA        NA        NA        NA        NA
## 6         NA         NA    NA      NA        NA        NA        NA        NA
##   PP11L PP11L1 PP11M PP11N PP11O PP11P PP11Q PP11R PP11S PP11T   P21 DECOCUR
## 1    NA     NA    NA    NA    NA    NA    NA    NA    NA    NA  1500       1
## 2    NA     NA    NA    NA    NA    NA    NA    NA    NA    NA  9500       5
## 3    NA     NA    NA    NA    NA    NA    NA    NA    NA    NA  7000       4
## 4    NA     NA    NA    NA    NA    NA    NA    NA    NA    NA  8000       4
## 5    NA     NA    NA    NA    NA    NA    NA    NA    NA    NA  6000       3
## 6    NA     NA    NA    NA    NA    NA    NA    NA    NA    NA 14000       7
##   IDECOCUR RDECOCUR GDECOCUR PDECOCUR ADECOCUR PONDIIO TOT_P12  P47T DECINDR
## 1        1        1        1       NA        1    1873       0  1500       1
## 2        5        5        5       NA        5     825       0  9500       5
## 3        4        4        3       NA        4    1494      -9    -9      12
## 4        5        4        4       NA        4    1471       0  8000       5
## 5        4        3        3       NA        3    1345       0  6000       4
## 6        8        7        7       NA        7    1741       0 21000       9
##   IDECINDR RDECINDR GDECINDR PDECINDR ADECINDR PONDII V2_M V3_M V4_M V5_M V8_M
## 1        1        1        1       NA        1   1386    0    0    0    0    0
## 2        6        5        5       NA        5   1130    0    0    0    0    0
## 3       12       12       12       NA       12      0    0    0    0    0    0
## 4        5        5        5       NA        5   1629    0    0    0    0    0
## 5        4        4        3       NA        4   1270    0    0    0    0    0
## 6        9        9        9       NA        9   2079    0    0    0    0    0
##   V9_M V10_M V11_M V12_M V18_M V19_AM V21_M T_VI   ITF DECIFR IDECIFR RDECIFR
## 1    0     0     0     0     0      0     0    0     0     NA      NA      NA
## 2    0     0     0     0     0      0     0    0  9500      2       2       2
## 3    0     0     0  3000     0      0     0 3000     0     NA      NA      NA
## 4    0     0     0     0     0      0     0    0     0     NA      NA      NA
## 5    0     0     0     0     0      0     0    0  6000      1       1       1
## 6    0     0     0     0     0      0     0    0 21000      6       7       7
##   GDECIFR PDECIFR ADECIFR  IPCF DECCFR IDECCFR RDECCFR GDECCFR PDECCFR ADECCFR
## 1      NA      NA      NA     0     NA      NA      NA      NA      NA      NA
## 2       2      NA       2  9500      7       7       7       7      NA       8
## 3      NA      NA      NA     0     NA      NA      NA      NA      NA      NA
## 4      NA      NA      NA     0     NA      NA      NA      NA      NA      NA
## 5       1      NA       1  2000      1       1       1       1      NA       1
## 6       6      NA       7 21000     10      10      10      10      NA      10
##   PONDIH  Sexo Establecimiento
## 1      0 Varón         Privado
## 2   1196 Mujer         Estatal
## 3      0 Varón         Privado
## 4      0 Mujer         Privado
## 5   1578 Varón         Privado
## 6   2137 Mujer         Privado

Para graficar un suavizado de las series, se utiliza la función geom_smooth(). Con suavizado nos referimos al gráfico de un modelo realizado sobre los datos, que estima el valor en el punto x,y (para el grupo). Las regresiones lineales son un ejemplo de esto, aunque no el único, ni el que viene por default.

ggplot(ggdata, aes(CH06, P21, colour = Sexo, shape = Sexo, alpha = P21))+
  geom_smooth() + 
  labs(
    x = 'Edad',
    y = 'ingreso',
    title = 'Ingreso por ocupación principal',
    subtitle = 'Según edad, nivel educativo y sexo') +
  theme_minimal()+
  scale_y_continuous(labels = comma)+
  scale_alpha(guide = FALSE)+
  facet_grid(.~NIVEL_ED)

Si corremos el comando geom_smooth() por default, nos advierte que esta utilizando el método GAM, de general additive models.

el sombreado gris que envuelve cada línea es el intervalo de confianza de dicho punto (95% por default).

También podemos utilizar métodos lineales, agregando el parámetro method = 'lm'. Haciendo esto, el gráfico muestra una regresión lineal simple. Si queremos otro tipo de regresión lineal, le podemos explicitar la fórmula.
En el ejemplo siguiente, utilizamos la formula $y = _0 +_1x +_2 x^2 $.

ggplot(ggdata, aes(CH06, P21, colour = Sexo, weight = PONDIIO)) +
  geom_smooth(method = "lm", formula = y ~ poly(x, 2)) +
  labs(x = 'Edad',
       y = 'ingreso',
       title = 'Regresion cuadrática del Ingreso por ocupación principal respecto de la Edad',
       subtitle = 'Según Nivel educativo y sexo') +
  theme_minimal()+
  facet_grid(. ~ NIVEL_ED)

Si quisiéramos, además de ver la relación entre ingreso, Edad, Sexo y Nivel educativo, incorporar el tipo de establecimiento,público o privado. Podemos facetear el gráfico por dos variables en lugar de una, lo que crea una matriz de gráficos según los cruces.

ggplot(ggdata, aes(CH06, P21, colour = Establecimiento, weight = PONDIIO)) +
  geom_smooth(method = "lm") +
  labs(
  x = 'Edad',
  y = 'ingreso',
  title = 'Tendencia del ingreso por ocupación principal',
  subtitle = 'Según edad, nivel educativo, sexo y tipo de establecimiento') +
  theme_minimal()+
  facet_grid(Sexo ~ NIVEL_ED)

Guardando la imagen en el directorio de trabajo.

ggsave(filename = paste0("Resultados", "regresion lineal.png"),scale = 2)