Limpiamos la memoria y creamos los directorios de trabajo
rm(list=ls())
# Funcion para obtener la direccion del Script Obtengo la ubicación del Script en el Disco
dir <- paste0(dirname(rstudioapi::getActiveDocumentContext()$path),"/")
# A partir del objeto dir, creo un objeto con la dirección de la carpeta que contiene los microdatos y otro con la que contendrá los resultados.
bases.dir <- paste0(dirname(dir),"/Fuentes/")
resultados.dir <- paste0(dirname(dir),"/Resultados/")
Rbase tiene algunos comandos genéricos para realizar gráficos, que se adaptan al tipo de información que se le pide graficar, por ejemplo:
# iris es un set de datos clásico, que ya viene incorporado en R
plot(iris)
data(iris)
plot(iris$Sepal.Length,type = "p")
plot(iris$Sepal.Length,type = "l")
plot(iris$Sepal.Length,type = "b")
hist(iris$Sepal.Length, col = "lightsalmon1", main = "Histograma")
Si queremos grabar los gráficos en la carpeta resultados. utilizamos la variable que creamos resultados.dir y la función PNG
archivo <- paste0(resultados.dir, "grafico1.PNG")
archivo
[1] "C:/temp/Trabajos/Curso R/Resultados/grafico1.PNG"
png(archivo)
plot(iris$Sepal.Length,type = "b")
dev.off()
null device
1
La función png() abre el dispositivo de imagen, luego podemos hacer los gráficos, y a continuación, con dev.off() se cierra el dispositivo y se graban los gráficos.
Los gráficos del R base son útiles para escribir de forma rápida y obtener alguna información mientras trabajamos. Muchos paquetes estadísticos permiten mostrar los resultados de forma gráfica con el comando plot (por ejemplo, las regresiones lineales lm()).
Sin embargo, existen librerías mucho mejores para crear gráficos de nivel de publicación. La más importante es ggplot2, que a su vez tiene extensiones mediante otras librerías.
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.
El operador + nos permite incorporar nuevas capas al gráfico.
El comando ggplot() nos permite definir los datos y las variables (x,y,color,forma,etc).
geom_col(), de línea, geom_line(), de puntos,geom_point(), boxplot, geom_boxplot())labs()theme()scale_y_continuous,scale_x_discretefacet_wrap(),facet_grid()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)
ggplot(data = iris, aes(x = Sepal.Length, fill = Species))+
geom_histogram(alpha=0.75, binwidth = .5)+
facet_wrap(~Species)+
labs(title = "Histograma por especie")+
theme(legend.position = 'none')
A continuación replicaremos dos gráficos del Informe Técnico de distribución del ingreso ingresos.
Cargo las librerías que voy a necesitar
library(tidyverse) # tiene ggplot, dplyr, tidyr, y otros
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()'
Levanto las bases. Como el gráfico de Gini tiene trimestres anteriores, necesito los datos de varios trimestres. Para evitar cargar mucha información demás, al mismo tiempo que lo levanto, selecciono las columnas que necesito
Individual_t117 <- read.table(paste0(bases.dir,"usu_individual_t117.txt"),
sep=";", dec=",", header = TRUE, fill = TRUE)
Individual_t216 <- read.table(paste0(bases.dir,"usu_individual_t216.txt"),
sep=";", dec=",", header = TRUE, fill = TRUE) %>%
select(ANO4,TRIMESTRE, IPCF, PONDIH)
Individual_t316 <- read.table(paste0(bases.dir,"usu_individual_t316.txt"),
sep=";", dec=",", header = TRUE, fill = TRUE)%>%
select(ANO4,TRIMESTRE, IPCF, PONDIH)
Individual_t416 <- read.table(paste0(bases.dir,"usu_individual_t416.txt"),
sep=";", dec=",", header = TRUE, fill = TRUE)%>%
select(ANO4,TRIMESTRE, IPCF, PONDIH)
Junto todas las bases en una sola tabla y calculo el gini para cada período
library(reldist) #para la función 'gini'
gini <- bind_rows(Individual_t216,
Individual_t316,
Individual_t416,
Individual_t117) %>%
select(ANO4,TRIMESTRE, IPCF, PONDIH) %>%
mutate(periodo = paste(ANO4, TRIMESTRE, sep = "\n")) %>%
group_by(periodo) %>%
summarise(gn = gini(IPCF, weights= PONDIH)) %>%
ungroup()
Con los gini calculados, podemos graficar
ggplot(data = gini, aes(x = periodo, y = gn)) +
geom_point()
Con algunos chiches más
ggplot(gini, aes(x = periodo, y = gn, group = 'gini', label= round(gn,3))) +
labs(x = "Trimestre", y = "Coeficiente de Gini", title = "Coeficiente de Gini", subtitle = "Según trimestre", caption = "Fuente: EPH")+
geom_line( size= 1 )+
geom_point(aes(shape = periodo, color = periodo),size= 3)+ #puedo definir aes() en cada tipo de gráfico
geom_text_repel(nudge_x = .2)+
theme_minimal()+
theme(legend.position = "none")
ggsave(filename = paste0(resultados.dir, "gini.png"))
Saving 7.23 x 4.46 in image
Gráfico 2. Población total según escala de ingreso individual por fuente y sexo. Total aglomerados urbanos. Primer trimestre 2017
TVI : MONTO TOTAL DE INGRESOS NO LABORALES
Totp12+P21 MONTO DE INGRESO DE LA OCUPACIÓN PRINCIPAL.+ MONTO DE INGRESO DE OTRAS OCUPACIONES.
Tengo que calcular el decil de ingreso de P47T (MONTO DE INGRESO TOTAL INDIVIDUAL). Para ello, primero hay que perturbar la variable para que no queden muchas personas con el mismo ingreso exacto.
Luego, calculo la proporción del ingreso laboral (expandido por PONDII) y del ingreso no laboral (también expandido), según decil y género
library(statar) # Para la función xtile
datagraf_2 <-Individual_t117 %>%
select(P47T,T_VI, TOT_P12, P21 , PONDII, CH04) %>%
filter(!is.na(P47T), P47T > 0 ) %>%
mutate(P47T_decil = P47T+runif(nrow(.),min = -.01,max =.01), # Perturbo la variable
DECINDR = xtile(P47T_decil,n=10,w = PONDII),
ingreso_laboral = as.numeric(TOT_P12 + P21),
ingreso_no_laboral = as.numeric(T_VI),
ingreso_total = ingreso_laboral + ingreso_no_laboral,
CH04 = case_when(CH04 == 1 ~ "Varon",
CH04 == 2 ~ "Mujer",
FALSE ~ "Otro") ) %>%
group_by(DECINDR, CH04) %>%
summarise('ingreso laboral' = sum(ingreso_laboral*PONDII)/sum(ingreso_total*PONDII),
'ingreso no laboral' = sum(ingreso_no_laboral * PONDII)/sum(ingreso_total*PONDII)) %>%
gather(tipo_ingreso, monto,3:4 )
datagraf_2
ggplot(datagraf_2, aes(CH04, monto, fill = tipo_ingreso,
label = sprintf("%1.1f%%", 100*monto)))+
geom_col(position = "stack", alpha=0.6) +
geom_text(position = position_stack(vjust = 0.5), size=3)+
labs(x="",y="Porcentaje")+
theme_tufte()+
scale_fill_fivethirtyeight()+
scale_y_continuous(labels = percent)+
theme(legend.position = "bottom",
legend.title=element_blank(),
axis.text.x = element_text(angle=25))+
facet_grid(.~DECINDR)
ggsave(filename = paste0(resultados.dir, "ingreso por decil.png"),scale = 2)
Saving 14.5 x 8.92 in image
En los gráficos utilizamos extensiones de ggplot:
geom_text_repel() y scale_fill_fivethirtyeight()theme_tufte()simplemente debemos recordar cargar las librerías si queremos utilizar esas funciones.
Los gráficos de barras, línea o de torta son fácilmente reproducibles en un excel, con información agregada. Sin embargo, hay cosas que no son replicables en excel:
facet_wrap()color =fill =shape =size =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').
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.
class(Individual_t117$NIVEL_ED)
[1] "integer"
class(Individual_t117$CH04)
[1] "integer"
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))
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")
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")
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 ~ 'Peampeana',
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(.)))
datagraf
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")
ggsave(filename = paste0(resultados.dir, "Kernel_1.png"),scale = 2)
Saving 14.5 x 8.92 in image
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")
ggsave(filename = paste0(resultados.dir, "Kernel_1.png"),scale = 2)
Saving 14.5 x 8.92 in image
El eje y no tiene demasiada interpretabilidad en los Kernel, porque hace a la forma en que se construyen las distribuciones.
Extensión de ggplot: librería : ggjoy
Esta extensión aprovecha que el eje y no es importante, y lo utiliza para apilar las distribuciones que se están comparando de forma más prolija.
Si por ejemplo queremos comparar la distribución del ingreso laboral según región:
library(ggjoy)
datagraf3 <- datagraf2 %>% filter(Tipo_ingreso == "ingreso_laboral")
ggplot(datagraf3, aes(
x = Ingreso,
y = REGION,
weights = PONDII,
group = REGION,
fill = REGION
)) +
geom_joy(alpha=0.6, bandwidth = 1500)+
labs(x="", y="",
title="Distribución del ingreso laboral según región",
caption = "Fuente: Encuesta Permanente de Hogares")+
scale_x_continuous(limits = c(0,35000))+
theme_tufte()+
scale_fill_gdocs()+
theme(legend.position = "none",
legend.title = element_blank(),
plot.title = element_text(size = 12))
ggsave(filename = paste0(resultados.dir, "Kernel_2.png"),scale = 2)
Saving 14.5 x 8.92 in image
Para realizar estos gráficos, vamos a modificar un poco los datos:
levels(). El “\n”" es un caracter especial que permite que el string continúe en la siguiente línea.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'))
ggdata
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)
ggsave(filename = paste0(resultados.dir, "regresion lineal.png"),scale = 2)
Saving 16 x 10 in image