Textos disponibles en la biblioteca de CCSS de la PUCP para el uso de ggplot2
Chang, Winston. 2012. R Graphics Cookbook. Sebastopol, CA: O’Reilly Media.
Field, Andy P. 2012. Discovering statistics using R. London; Thousand Oaks, Calif: Sage.
Wickham, Hadley. 2009. Ggplot2: elegant graphics for data analysis. New York: Springer.
Un gráfico en ggplot2 puede tener varias capas, en su conjunto, las capas forman el gráfico al combinar:
Base de datos para estos ejercicios: Familia y roles de género 2012, a descargar de:
http://iop-data.pucp.edu.pe/busqueda/encuesta/71?
Descomprimir y grabar el archivo SPSS en el directorio de trabajo de R
# Importar la base de datos del SPSS a un data frame de R
library(foreign)
genero <- as.data.frame(read.spss("IOP_1212_01_B.sav"))
## re-encoding from UTF-8
El esquema básico de la gramática de ggplot es:
ggplot(data.frame, aes(x = variable)) + geom_forma()
library(ggplot2)
ggplot(genero, aes(x = SEXO)) + geom_bar()
gr1 <- ggplot(genero, aes(x = SEXO)) + geom_bar()
gr1 + xlab("Sexo del entrevistado") + ylab ("Número de casos")# etiquetas de los ejes
gr1 + xlab("Sexo del entrevistado") + ylab ("Número de casos") +
ggtitle("Sexo del entrevistado")
Podemos cambiar cómo se ven algunos elementos, por ejemplo, que las barras sean más pequeñas, en este caso la mitad (0.5) del tamaño por defecto:
gr1 <- ggplot(genero, aes(x = SEXO)) + geom_bar(width=0.5)
gr1 + xlab("Sexo del entrevistado") + ylab ("Número de casos") +
ggtitle("Sexo del entrevistado")
Con la opción “colour” y “fill” en el comando geom_bar podemos cambiar el color del controno de las barras y de su relleno
gr1 <- ggplot(genero, aes(x = SEXO)) + geom_bar(width=0.5, colour="blue", fill="red")
gr1 + xlab("Sexo del entrevistado") + ylab ("Número de casos") +
ggtitle("Sexo del entrevistado")
Los temas (theme) son un conjunto de opciones predefinidas sobre la apariencia de los objetos en ggplot. El tema por defecto del ggplot dibuja el gráfico sobre un fondo gris. Podemos cambiarlo a blanco y negro añadiendo el comando theme_bw()
gr1 <- ggplot(genero, aes(x = SEXO)) + geom_bar(width=0.5, colour="blue", fill="red")
gr1 + xlab("Sexo del entrevistado") + ylab ("Número de casos") +
ggtitle("Sexo del entrevistado") + theme_bw()
Hacer un gráfico de barras de sexo, pero con porcentajes en el eje vertical. Primero preparar los datos:
tab.sex1 <- as.data.frame(prop.table(table(genero$SEXO))*100)
tab.sex1
## Var1 Freq
## 1 Masculino 48.96093
## 2 Femenino 51.03907
colnames(tab.sex1) <- c("Sexo", "Porcentaje")
Ahora el gráfico:
ggplot(tab.sex1, aes(x=Sexo, y=Porcentaje)) + geom_bar(stat="identity")
gr2 <- ggplot(tab.sex1, aes(x=Sexo, y = Porcentaje)) +
geom_bar(stat="identity", width=0.5, fill = "grey")
gr2 + xlab(NULL) + ylab("% de entrevistados") +
ggtitle("Distribución de los entrevistados\n por sexo (%)") + theme_bw()
library(scales) # requiere instalar el paquete "scales"
gr2.a <- ggplot(genero, aes(SEXO)) +
geom_bar(aes(SEXO, (..count..)/sum(..count..)), width=0.5, fill = "grey")
gr2.a + scale_y_continuous(labels=percent) + xlab(NULL) +
ylab("% de casos") + ggtitle("Distribución de los\n entrevistados por sexo") + theme_bw()
La distribución de frecuencias de la pregunta P36 según sexo
ggplot(genero, aes(P36, fill=SEXO)) + geom_bar(position="dodge")
¿Cómo quitamos “NS/NR” y establecemos que la escala del eje vertical sean %?
gr3 <- ggplot(genero[genero$P36!="NS/NR", ], (aes(P36, fill=SEXO))) +
geom_bar(aes(P36, (..count..)/sum(..count..)), position="dodge") +
scale_y_continuous(labels=percent) + scale_fill_grey() + theme_bw()
gr3
Completamos el gráfico
gr3 + xlab(NULL) + ylab("% de casos") + ggtitle("¿Los demás miembros del hogar deberían pagarle un sueldo o salario\n al miembro del hogar que se encarga de las tareas domésticas?:\n % de respuestas según sexo del entrevistado")
Las facetas o “facets” en ggplot me permiten reproducir el mismo gráfico en diferentes niveles de un factor. Hagamos un gráfico de la distribución en % de la pregunta P51D, para los diferentes dominios geográficos
# Primero preparamos los datos en una tabla que convertimos en data frame
tab.5 <- as.data.frame(prop.table(table(genero$P51D, genero$DOMINIO), 2)*100)
tab.5
## Var1 Var2 Freq
## 1 Muy de acuerdo Lima-Callao 0.8928571
## 2 De acuerdo Lima-Callao 18.7500000
## 3 En desacuerdo Lima-Callao 62.0535714
## 4 Muy en desacuerdo Lima-Callao 13.1696429
## 5 NS / NR Lima-Callao 5.1339286
## 6 Muy de acuerdo Norte 3.4375000
## 7 De acuerdo Norte 25.9375000
## 8 En desacuerdo Norte 55.3125000
## 9 Muy en desacuerdo Norte 10.0000000
## 10 NS / NR Norte 5.3125000
## 11 Muy de acuerdo Sur 7.3469388
## 12 De acuerdo Sur 31.0204082
## 13 En desacuerdo Sur 43.6734694
## 14 Muy en desacuerdo Sur 13.0612245
## 15 NS / NR Sur 4.8979592
## 16 Muy de acuerdo Centro 13.3333333
## 17 De acuerdo Centro 22.8571429
## 18 En desacuerdo Centro 35.2380952
## 19 Muy en desacuerdo Centro 20.9523810
## 20 NS / NR Centro 7.6190476
## 21 Muy de acuerdo Oriente 0.0000000
## 22 De acuerdo Oriente 20.0000000
## 23 En desacuerdo Oriente 72.9411765
## 24 Muy en desacuerdo Oriente 3.5294118
## 25 NS / NR Oriente 3.5294118
colnames(tab.5) <- c("Rptas", "Dominio", "Pct")
Este sería en gráfico de base:
gr4 <- ggplot(tab.5, aes(x=Rptas, y=Pct)) + geom_bar(stat="identity")
gr4
Hacemos las facetas verticales
gr4 + facet_grid(Dominio ~.)
Si las queremos horizontales:
gr4 + facet_grid(.~ Dominio)
Si queremos que roten a lo largo de columnas y filas:
gr4 + facet_wrap(~ Dominio)
Podemos rotar el gráfico para que se aprecien mejor las etiquetas de respuestas
gr4 + coord_flip() + facet_wrap(~ Dominio)
Histograma básico de la pregunta P19A
ggplot(genero, aes(P19A)) + geom_histogram()
## stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.
Amplitud de los intervalos del histograma
range(genero$P19A, na.rm=TRUE)
## [1] 0 168
168/30
## [1] 5.6
Cambiamos la amplitud del intervalo
ggplot(genero, aes(P19A)) + geom_histogram(binwidth = 10)
hist1 <- ggplot(genero, aes(P19A)) + geom_histogram(binwidth = 10,
fill="red", colour="black")
hist1
hist1 + facet_grid(SEXO ~.)
Otra forma de ver la distribución de una variable cuantitativa, sobre la base del cálculo de densidades a partir del histograma:
## Las sintaxis nos dan el mismo resultado. La segunda evita dibujar la línea de abajo
ggplot(genero, aes(P23)) + geom_density()
ggplot(genero, aes(P23)) + geom_line(stat="density")
Distribución de la edad en la que se casó según NSE
ggplot(genero, aes(P23)) + geom_line(stat="density") + facet_grid(NSEGrup ~.)
Distribución de la edad en la que se casó según NSE y Sexo
ggplot(genero, aes(P23)) + geom_line(stat="density") + facet_grid(NSEGrup ~ SEXO)
Objetivo: generar un gráfico de líneas que muestre cómo varía el % de personas que están en desacuerdo con la frase “Jamás tendría un amigo homosexual o una amiga lesbiana” (P51D)
Paso 1: Crear una variable categórica que agrupe las edades de los entrevistados en intervalos
edad <- genero$EDAD
gr.edad <- as.factor(cut(edad, breaks = c(18, 25, 35, 45, 55, 92),
include.lowest = TRUE))
table(gr.edad)
## gr.edad
## [18,25] (25,35] (35,45] (45,55] (55,92]
## 288 283 258 173 201
Paso 2: Recodificamos la variable P51D en dos grupos, lo que están de acuerdo, los que están en desacuerdo. Los NS/NR los pasamos como NA
table(genero$P51D)
##
## Muy de acuerdo De acuerdo En desacuerdo Muy en desacuerdo
## 47 284 661 148
## NS / NR
## 63
p51dr <-as.numeric(genero$P51D)
table(p51dr)
## p51dr
## 1 2 3 4 5
## 47 284 661 148 63
library(car)
p51dr <- factor(recode(p51dr, "1:2=1; 3:4=2; 5=NA")) # recodificamos
levels(p51dr) <- c("De acuerdo", "En desacuerdo")
Paso 3: Generamos una tabla de % cruzados de respuestas a la pregunta P51D según grupos de edad y la convertimos en un data frame
tab1 <- prop.table(table(gr.edad, p51dr), 1)*100
tab1
## p51dr
## gr.edad De acuerdo En desacuerdo
## [18,25] 21.58273 78.41727
## (25,35] 26.56827 73.43173
## (35,45] 29.33884 70.66116
## (45,55] 35.22013 64.77987
## (55,92] 37.89474 62.10526
Paso 4: Convertimos la tabla generada en un data frame
df.tab1 <- data.frame(tab1)
df.tab1
## gr.edad p51dr Freq
## 1 [18,25] De acuerdo 21.58273
## 2 (25,35] De acuerdo 26.56827
## 3 (35,45] De acuerdo 29.33884
## 4 (45,55] De acuerdo 35.22013
## 5 (55,92] De acuerdo 37.89474
## 6 [18,25] En desacuerdo 78.41727
## 7 (25,35] En desacuerdo 73.43173
## 8 (35,45] En desacuerdo 70.66116
## 9 (45,55] En desacuerdo 64.77987
## 10 (55,92] En desacuerdo 62.10526
Nos interesa representar sólo los % en desacuerdo. Para ello seleccionamos del data frame unicamente los registros que corresponden a los “desacuerdo”
df.tab2 <- subset(df.tab1, p51dr=="En desacuerdo")
df.tab2
## gr.edad p51dr Freq
## 6 [18,25] En desacuerdo 78.41727
## 7 (25,35] En desacuerdo 73.43173
## 8 (35,45] En desacuerdo 70.66116
## 9 (45,55] En desacuerdo 64.77987
## 10 (55,92] En desacuerdo 62.10526
Ahora contamos con los datos para elaborar el gráfico de líneas:
graf.linea1 <- ggplot(df.tab2, aes(x=gr.edad, y=Freq, group=1)) + geom_line()
graf.linea1
Podemos añadir puntos al la línea para marcar mejor el dato correspondiente a los grupos de edad:
graf.linea2 <- graf.linea1 + geom_line() + geom_point()
graf.linea2
Podemos ajustar la escala del eje Y para evitar demasiadas distorsiones y añadir títulos a los ejes y al gráfico.
graf.linea2 + ylim(0, 100) + xlab("Grupos de edad") + ylab("% de casos") +
ggtitle("Porcentaje de personas en desacuerdo con la afirmación:\n \"Jamás tendría un amigo homosexual o una amiga lesbiana\",\n según grupo de edad")
Una alternativa a un gráfico de barras, puede ser un gráfico de puntos, conocido como “Cleveland Dot Plot”. Observe este data frame que contiene el promedio de la edad considerada como ideal para que una mujer se case según dominio geográfico:
# Sintaxis para generar la tabla de datos
eideal.m <- genero$P1
eideal.m[genero$P1==99] <- NA
df2 <- data.frame(tapply(eideal.m, genero$DOMINIO, mean, na.rm = TRUE))
df2$dominio <- rownames(df2)
colnames(df2) <- c("mean.ideal.m", "dominio")
## Tabla de datos en forma de un data.frame
df2
## mean.ideal.m dominio
## Lima-Callao 26.71065 Lima-Callao
## Norte 25.83442 Norte
## Sur 26.26250 Sur
## Centro 26.22680 Centro
## Oriente 25.04762 Oriente
Aquí el grafico de puntos tipo “Cleveland”:
ggplot(df2, aes(x=mean.ideal.m, y=dominio)) +
geom_point(size=3)
El mismo gráfico con los datos ordenados según la magnitud de la media
ggplot(df2, aes(x=mean.ideal.m, y=reorder(dominio, mean.ideal.m))) +
geom_point(size=3)