Capítulo 16 Recursos extras

16.1 Incursión aleatoria

Antes de acabar esta breve introducción a R merece la pena hablar de «lo aleatorio» y su generación en R.

¿Cómo se define la aleatoriedad?

Si alguna vez has interactuado con matemáticos o estadísticos (Dios te libre), seguramente es una palabra que les hayas escuchado mentar: aleatoriedad. Existen múltiples definiciones, y este manual tampoco pretende ser un tratado de filosofía de la ciencia, pero podemos definir la aleatoriedad de la siguiente manera:

 

GLOSARIO: aleatoriedad

Propiedad de todo proceso cuyo resultado final no se puede conocer con exactitud - a nivel individual o particular - antes de que se realice, aunque las condiciones iniciales se mantengan constantes (ejemplo: lanzar un dado).

¿Qué NO significa la palabra «aleatorio»?

🛑 NO tiene que implicar algo caótico.
🛑 NO significa que no se pueda predecir a nivel de conjunto.
🛑 NO significa que carezca de un patrón de comportamiento.  

El ejemplo perfecto para entender las implicaciones de algo aleatorio es un dado, ya que no podemos saber con exactitud cuál será la siguiente tirada, pero tiene un patrón: si tiramos un millón de veces, aproximadamente un sexto del total de tiradas serán un 1.

 

En el análisis estadístico y en la programación en R nos vamos a encontrar con múltiples situaciones en las que lo aleatorio juega un papel importante, y aunque este sea un tutorial muy básico e introductorio, creo que es interesante conocer algunas formas muy sencillas de generar números aleatorios (o…no tanto, ahora llegamos a la Sección 16.2).

Empecemos por lo más simple: vamos a simular tiradas de una moneda, asumiendo que solo tenemos dos opciones (eliminando la opción de caer de canto). Cuando tiramos una moneda es un experimento aleatorio, ya que no sabemos el resultado exacto de la siguiente tirada, pero sí sabemos que la probabilidad teórica es de 50-50, y que las únicas opciones a elegir son cara y cruz.

Una forma de ver el experimento de lanzar una moneda es pensar que tenemos una urna con dos bolas (cara y cruz), y empezamos a sacar bolas de la urna (permitiendo que al sacar una bola, se pueda devolver a la urna de nuevo). Eso es precisamente lo que hace la función sample(), una función que nos seleccionará «aleatoriamente» elementos de una urna.

  • x: los elementos distintos que tiene para elegir, que en nuestro caso serán "cara" y "cruz".
  • size: el número de bolas que queremos sacar de la urna.
  • replace: si tras extraer devolvemos la bola a la urna (replace = TRUE) o si se queda fuera (replace = FALSE, valor por defecto).
  • prob: la probabilidad que tiene cada elemento en caso de no ser equiprobables (valor por defecto).
# Tiramos 20 veces una moneda
sample(x = c("cara", "cruz"), size = 20, replace = TRUE)
##  [1] "cara" "cruz" "cara" "cruz" "cara" "cara" "cruz" "cara" "cara" "cruz"
## [11] "cara" "cara" "cruz" "cara" "cruz" "cruz" "cruz" "cara" "cruz" "cruz"

Fíjate que hemos indicado explícitamente replace = TRUE para decirle que aunque solo tengamos dos opciones, vamos a permitir que tras extraer una bola, la apuntemos, y la volvamos a introducir (puede salir de nuevo). ¿Qué sucede si replace = FALSE (su valor por defecto)?

# Tiramos 20 veces una moneda SIN reemplazamiento
sample(x = c("cara", "cruz"), size = 20)
## Error in sample.int(length(x), size, replace, prob): cannot take a sample larger than the population when 'replace = FALSE'

Al tener solo dos opciones, y no permitir que al extraer bolas vuelvan a la urna, tras extraer las dos únicas bolas, el proceso no puede continuar hasta los 20 lanzamientos.

Como seguramente te hayas percatado, lanzar una moneda es un experimento dicotómico, y dichos experimentos tienen una gran ventaja en programación y es que podemos escribirlo en binario: 0 para lo que llamemos fracaso (cara, por ejemplo), 1 para lo que llamemos éxito (cruz).

Generar experimentos dicotómicos de forma binario nos permite hacer cálculos sobre las tiradas de forma muy sencilla e intuitiva, ya que nos permite pasar de tener cadenas de texto a números.

# Tiramos 50 veces una moneda: 0 es cara, 1 es cruz
n_tiradas <- 50
tiradas <- sample(x = 0:1, size = n_tiradas, replace = TRUE)
tiradas
##  [1] 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 0 0 0 1 0 1 1 0 0 1 1 0 0 0 0 1 0 0 1
## [39] 1 1 1 0 0 1 0 0 1 1 1 1
# Cantidad de cruces: sumamos los 1's
sum(tiradas)
## [1] 27
# Cantidad de caras: lo que son cruces
n_tiradas - sum(tiradas)
## [1] 23
# % de caras
cat(paste0(100 * sum(tiradas) / n_tiradas, "% de cruces"))
## 54% de cruces

El argumento prob = ... nos permite generar experimentos que sean dicotómicos pero que no sean equiprobables, algo similar a lanzar una moneda trucada (por ejemplo, 30% caras y 70% cruces). Nótese como dichas probabilidades deben ser introducidas como proporciones (divididas entre 100).

# Tiradas de una moneda trucada
tiradas <- sample(x = 0:1, size = n_tiradas, replace = TRUE, prob = c(0.3, 0.7))

# % de caras
cat(paste0(100 * sum(tiradas) / n_tiradas, "% de cruces"))
## 78% de cruces

📝Ejercicio: ¿cómo simularías 200 tiradas de un dado?

  • Solución:
# Lo único que cambia son las opciones en la urna
sample(x = 1:6, size = 200, replace = TRUE)
##   [1] 6 3 5 2 5 3 2 2 3 5 5 6 4 5 3 5 3 5 4 3 1 5 3 5 1 3 4 2 4 6 3 1 4 4 6 1 3
##  [38] 6 6 6 6 2 1 6 5 4 1 2 2 4 3 2 5 5 6 3 1 5 3 6 4 6 6 5 2 1 1 4 1 1 4 5 1 3
##  [75] 6 1 2 4 1 3 2 4 1 3 3 4 6 1 6 1 2 1 3 2 6 2 6 1 3 5 6 6 3 2 6 4 1 6 1 2 6
## [112] 3 1 3 1 1 4 4 4 5 3 1 1 6 6 5 2 6 6 2 4 1 5 5 6 6 5 4 2 6 5 5 3 6 5 2 5 6
## [149] 1 5 3 3 4 3 1 2 6 4 2 3 6 2 6 2 4 5 2 6 5 6 1 3 5 3 6 6 1 4 4 3 2 3 3 4 6
## [186] 5 5 3 6 1 6 6 1 3 4 2 1 1 1 3

16.2 Pseudoaleatoriedad

Si has hecho varias pruebas con los códigos de arriba quizás ya hayas visto que cada vez que lanzas el código, el resultado es distinto, algo similar a lo que sucedería si lanzas una moneda. Prueba a ejecutar este código varias veces.

sample(0:1, size = 20, replace = TRUE)
##  [1] 1 0 1 0 1 1 0 1 0 0 0 1 0 1 0 0 1 0 0 0
sample(0:1, size = 20, replace = TRUE)
##  [1] 1 1 1 1 1 0 1 0 0 1 1 1 1 1 1 0 0 0 0 1
sample(0:1, size = 20, replace = TRUE)
##  [1] 1 0 0 1 0 1 1 0 0 0 1 1 1 1 0 1 1 1 0 0

¿Y si quisiéramos generar toda la clase la misma tirada de moneda?

Lo primero que quizás pienses es que es imposible, ya que al tirar una moneda en la vida real, nunca vamos a tener forma de garantizar que salgan las mismas tiradas a diferentes personas. Y efectivamente eso sería cierto si nuestros procesos generados hubiesen sido aleatorios, como en la vida real pero…no lo son.

Mientras esperamos a que lleguen al mainstream los ordenadores cuánticos, TODO lo que hay en tu ordenador es determínistico, ya que cualquier proceso se reduce a una secuencia de bits (0's y 1's) y un algoritmo (sin azar, cuyo resultado siempre será el mismo bajo las mismas condiciones iniciales). He aquí la decepción de tu vida: un ordenador «normal» NO puede generar procesos aleatorios, sino procesos y números PSEUDOALEATORIOS, basados en cadenas pseudoaleatorias generadas por un algoritmo determinístico.

Dichas secuencias aparentan ser aleatorias pero no lo son, y de hecho muchas son periódicas: si generamos el número suficiente de elementos de la cadena pseudoaleatoria volveremos al inicio. Muchos de los algoritmos disponibles para generar números aleatorios dependen, entre otros factores, de un valor inicial llamada semilla (normalmente obtenida a partir del reloj interno del ordenador): misma semilla, mismo resultado «aleatorio». Para fijar la semilla usaremos set.seed(), pasándole como argumento una secuencia de números (todos la misma).

set.seed(1234567)
sample(0:1, size = 20, replace = TRUE)
##  [1] 0 1 1 0 1 0 0 0 1 1 0 1 0 1 0 0 1 1 1 0
set.seed(1234567)
sample(0:1, size = 20, replace = TRUE)
##  [1] 0 1 1 0 1 0 0 0 1 1 0 1 0 1 0 0 1 1 1 0
set.seed(1234567)
sample(0:1, size = 20, replace = TRUE)
##  [1] 0 1 1 0 1 0 0 0 1 1 0 1 0 1 0 0 1 1 1 0

Siempre la misma tirada si la semilla inicial es la misma ya que las cadenas pseudoaleatorias que usa el ordenador para simular nuestras tiradas son idénticas.

16.3 Visualizando datos: incursión a ggplot2

Este curso es una pequeña introducción y no pretende ser un manual extenso ni detallado de R, así que no entraremos en profundidad en la parte visual. Pero si creo que merece la pena hacer una breve incursión al dataviz ya que una de las principales fortalezas de R frente a Python es el manejo de datos con tidyverse, entorno en el que se incluye el paquete ggplot2.

La visualización de datos o dataviz debería ser una parte fundamental de todo análisis de datos. No es solo que nuestro trabajo sea más presentable y estético (algo fundamental). La visualización de datos es fundamental para convertir el dato en información, y usar dicha información para contar una historia con nuestros datos: no solo importa lo que cuentas sino cómo lo cuentas).

Uno de los ejemplos más famosos para explicar la importancia de la visualización de datos en el análisis exploratorio es el conocido como cuarteto de Anscombe: cuatro pares de datos \((X, Y)\) con la misma media de todas las \(X\), la misma media de todas las \(Y\), la misma correlación en todos los pares y la misma recta de regresión si la pintásemos. Matemáticamente, con dichos indicadores, no podríamos distinguir un conjunto de datos de otro, pero al visualizarlos, son datos totalmente distintos. Algo similar sucede con el conjunto de datos Datasaurus que te visualizo debajo de estas líneas, conjunto creado por el experto en visualización de datos Alberto Cairo: mismas medias y varianzas, mismas correlaciones, pero datos totalmente distintos.

16.3.1 Grammar of graphics (gg): entendiendo la gramática ggplot2

La idea de la filosofía detrás del paquete ggplot2 (ya incluido en tidyverse) es entender los gráficos como parte integrada del flujo de procesamiento, depuración y modelado de los datos, dándoles una gramática Grammar of Graphics (ver https://ggplot2-book.org/introduction.html) que nos permite combinar diferentes elementos gráficos y ligarlos a los datos. El objetivo es empezar con un lienzo en blanco e ir añadiendo capas a tu gráfico, como harías por ejemplo en Photoshop, con la diferencia de que nuestras capas podemos ligarlas al conjunto de datos, tanto las capas estéticas como las estadísticas. Y dicho paquete nos permite hacerlo con la misma filosofía con la que hemos procesado los datos

Idea detrás de la «Grammar of graphics» de Wilkinson.

Imagen/gráfica 16.2: Idea detrás de la «Grammar of graphics» de Wilkinson.

La ventaja del sistema ggplot2 es poder mapear atributos estéticos (color, forma, tamaño) de objetos geométricos (puntos, barras, líneas) en función de los datos, añadiendo transformaciones de los datos, resúmenes estadísticos y transformaciones de las coordenadas.

Un gráfico se compondrá de las siguientes capas

  • Elementos geométricos (geom): puntos, líneas, barras, polígonos, etc.
  • Transformaciones estadísticas (stat): ordenar, resumir, agrupar, etc.
  • Elementos del espacio aesthetics (scale): color, forma, tamaño, leyenda, ejes, etc.
  • Sistema de coordenadas (coord): coordenadas, grids, etc.
  • Componer gráficas (facet): visualizar varias gráficas a la vez.
  • Temas (theme): fuente, tamaño de letra, subtítulos, captions, etc.

16.4 Primer intento: scatter plot o diagrama de puntos

Veamos un primer intento para entender la filosofía. Imagina que queremos dibujar un scatter plot o diagrama de (dispersión) de puntos. Para ello vamos a usar el conjunto de datos gapminder del paquete homónimo, un fichero con datos de esperanzas de vida, poblaciones y renta per cápita de distintos países en distintos momentos temporales.

library(gapminder)
gapminder
## # A tibble: 1,704 × 6
##    country     continent  year lifeExp      pop gdpPercap
##    <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
##  1 Afghanistan Asia       1952    28.8  8425333      779.
##  2 Afghanistan Asia       1957    30.3  9240934      821.
##  3 Afghanistan Asia       1962    32.0 10267083      853.
##  4 Afghanistan Asia       1967    34.0 11537966      836.
##  5 Afghanistan Asia       1972    36.1 13079460      740.
##  6 Afghanistan Asia       1977    38.4 14880372      786.
##  7 Afghanistan Asia       1982    39.9 12881816      978.
##  8 Afghanistan Asia       1987    40.8 13867957      852.
##  9 Afghanistan Asia       1992    41.7 16317921      649.
## 10 Afghanistan Asia       1997    41.8 22227415      635.
## # … with 1,694 more rows
glimpse(gapminder)
## Rows: 1,704
## Columns: 6
## $ country   <fct> "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", …
## $ continent <fct> Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, …
## $ year      <int> 1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987, 1992, 1997, …
## $ lifeExp   <dbl> 28.801, 30.332, 31.997, 34.020, 36.088, 38.438, 39.854, 40.8…
## $ pop       <int> 8425333, 9240934, 10267083, 11537966, 13079460, 14880372, 12…
## $ gdpPercap <dbl> 779.4453, 820.8530, 853.1007, 836.1971, 739.9811, 786.1134, …

Para empezar con algo sencillo filtraremos solo los datos del año 1997 haciendo uso de filter().

gapminder_1997 <- gapminder %>% filter(year == 1997)
gapminder_1997
## # A tibble: 142 × 6
##    country     continent  year lifeExp       pop gdpPercap
##    <fct>       <fct>     <int>   <dbl>     <int>     <dbl>
##  1 Afghanistan Asia       1997    41.8  22227415      635.
##  2 Albania     Europe     1997    73.0   3428038     3193.
##  3 Algeria     Africa     1997    69.2  29072015     4797.
##  4 Angola      Africa     1997    41.0   9875024     2277.
##  5 Argentina   Americas   1997    73.3  36203463    10967.
##  6 Australia   Oceania    1997    78.8  18565243    26998.
##  7 Austria     Europe     1997    77.5   8069876    29096.
##  8 Bahrain     Asia       1997    73.9    598561    20292.
##  9 Bangladesh  Asia       1997    59.4 123315288      973.
## 10 Belgium     Europe     1997    77.5  10199787    27561.
## # … with 132 more rows

Vamos a realizar un diagrama de puntos enfrentando en el eje y la población (variable pop) y en el eje x la renta per cápita (variable gdpPercap). ¿Qué necesitamos?

  • Datos: el conjunto filtrado gapminder_1997.
  • Mapeado: indicarle en aes() (aesthetics) las variables a pintar en cada coordenada.
  • Elegir geometría: puntos.
ggplot(gapminder_1997, aes(x = gdpPercap, y = pop)) +
  geom_point() # Geometría

Podemos hacer lo mismo pero cambiando el rol de las coordenadas, intercambiando lsa variables

ggplot(gapminder_1997, aes(y = gdpPercap, x = pop)) +
  geom_point()

Y podemos repetirlo enfrentando ahora la población en el eje X y la experanza de vida en el eje Y (variable lifeExp).

ggplot(gapminder_1997, aes(y = lifeExp, x = pop)) +
  geom_point()

A veces nos puede ser más conveniente representar alguna de las variables en escala logarítmica (importante: indícalo siempre en el gráfico), lo que podemos hacer facilmente con scale_x_log10() y scale_y_log10()

ggplot(gapminder_1997, aes(y = lifeExp, x = pop)) +
  geom_point() + scale_x_log10()

¿Cómo podemos dar color y tamaño a nuestro gráfico?

La opción más sencilla es indicándole, dentro de geom_point() el color de la geometría con color = ... (en este caso, el color del punto), mediante un color fijo, bien sea con alguno de los colores reservados que tiene R, bien sea con su código hexadecimal

# Color con palabra reservada
ggplot(gapminder_1997, aes(y = lifeExp, x = pop)) +
  geom_point(color = "red") +
  scale_x_log10()
# Color en hexadecimal, de la página https://htmlcolorcodes.com/es/
ggplot(gapminder_1997, aes(y = lifeExp, x = pop)) +
  geom_point(color = "#2EA2D8") +
  scale_x_log10()

De la misma manera podemos indicarle el tamaño de la geometría (en este caso del punto) con size = ..., incluso la transparencia que queremos para un color dado con alpha = ... (entre 0 - transparente - y 1 - totalmente opaco).

# Color opaco
ggplot(gapminder_1997, aes(y = lifeExp, x = pop)) +
  geom_point(color = "#A02B85", size = 6) +
  scale_x_log10()
# alpha = 50%
ggplot(gapminder_1997, aes(y = lifeExp, x = pop)) +
  geom_point(color = "#A02B85", size = 6, alpha = 0.5) +
  scale_x_log10()

Dichos parámetros se los hemos pasado fijos, como si fuera un valor constante pero podemos mapear los aesthetics de un gráfico para que dependan de los datos, por ejemplo, asignándole un color a cada continente.

ggplot(gapminder_1997, aes(y = lifeExp, x = pop, color = continent)) +
  geom_point(size = 5) +
  scale_x_log10()

Podemos combinarlo con lo que hemos hecho anteriormente e indicarle además que queremos el tamaño en función de la renta, con cierto grado de transparencia.

ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.7) +
  scale_x_log10()

En lugar de jugar con el color, también podríamos añadir mapear las variables en función de la forma de la geometría con shape = ... (en realidad si tuviéramos suficientes variables podríamos incluir, solo con ejes + colores + tamaños + formas + transparencia, hasta 6 variables distintas).

ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           shape = continent, size = gdpPercap)) +
  geom_point(alpha = 0.7) +
  scale_x_log10()

Reflexionemos sobre el gráfico que acabamos de hacer

ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.7) +
  scale_x_log10()

Usando los datos hemos conseguido dibujar en un gráfico bidimensional 4 variables (pop y lifeExp en los ejes X,Y, continent como color y gdpPercap como tamaño de la geometría) con muy pocas líneas de código, y totalmente adaptado y flexible a nuestras necesidades. Respecto a los colores, si te fijas R ha elegido automáticamente la paleta de colores pero podemos indicarle alguna paleta concreta de varias maneras.

La primera y más inmediata es indicarle los colores manualmente.

ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.7) +
  scale_x_log10() +
  scale_color_manual(values = c("#A02B85", "#2DE86B", "#4FB2CA",
                                "#E8DA2D", "#E84C2D"))

Otra opción es elegir alguna de las paletas disponibles en el paquete ggthemes, como scale_color_economist(), scale_color_excel() o scale_color_tableau().

library(ggthemes)

# scale_color_economist()
ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  scale_color_economist()
# scale_color_excel()
ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  scale_color_excel()
# scale_color_tableau()
ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  scale_color_tableau()

También existen múltiples paquetes que nos proporcionan paletas de colores basados en películas (paquete harrypotter descargado desde el repositorio de Github), pájaros (paquete Manu) o cuadros (paquete {MetBrewer}).

devtools::install_github(repo = "https://github.com/aljrico/harrypotter")
library(harrypotter)
ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  scale_color_hp_d(option = "gryffindor") +
  labs(title = "Ejemplo de ggplot2",
       subtitle = "Paleta de Gryffindor",
       caption = "Autor: Javier Álvarez Liébana | Datos: gapminder")
ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  scale_color_hp_d(option = "hufflepuff") +
  labs(title = "Ejemplo de ggplot2",
       subtitle = "Paleta de Hufflepuff",
       caption = "Autor: Javier Álvarez Liébana | Datos: gapminder")
devtools::install_github("G-Thomson/Manu")
library(Manu)
ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  # paleta del pájaro Takahē - Porphyrio hochstetteri
  scale_colour_manual(values = get_pal("Takahe")) +
  labs(title = "Ejemplo de ggplot2",
       subtitle = "Paleta del pájaro Takahē - Porphyrio hochstetteri",
       caption = "Autor: Javier Álvarez Liébana | Datos: gapminder")
devtools::install_github("BlakeRMills/MetBrewer") 
library(MetBrewer)
MetBrewer::met.brewer("Renoir")
MetBrewer::met.brewer("Monet")
MetBrewer::met.brewer("Hokusai")
ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  scale_colour_manual(values = met.brewer("Klimt")) +
  labs(title = "Ejemplo de ggplot2",
       subtitle = "Paleta de cuadros de Klimt",
       caption = "Autor: Javier Álvarez Liébana | Datos: gapminder")

Los gráficos pueden además personalizarse añadiendo, por ejemplo, títulos y subtítulos de la gráfica con `labs()

ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  scale_color_tableau() +
  labs(title = "Ejemplo de ggplot2",
       subtitle = "Aprendiendo R sin morir en el intento",
       caption = "Autor: Javier Álvarez Liébana | Datos: gapminder")

De la misma manera podemos personalizar el título que vamos a dar a los ejes y también el título de las leyendas.

ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  scale_color_tableau() +
  labs(x = "Población", y = "Esperanza de vida",
       color = "Continente", size = "Renta per cápita",
       title = "Ejemplo de ggplot2",
       subtitle = "Población vs esperanza de vida (año 1997)",
       caption = "Autor: Javier Álvarez Liébana | Datos: gapminder")

Por último, podemos dividir/desagregar los gráficos (facetar) por variables, pintando por ejemplo un gráfico por continente, mostrando todos los gráficos a la vez pero por separado, con facet_wrap().

ggplot(gapminder_1997, aes(y = lifeExp, x = pop, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  facet_wrap(~ continent) +
  labs(x = "Población", y = "Esperanza de vida",
       color = "Continente", size = "Renta per cápita",
       title = "Ejemplo de ggplot2",
       subtitle = "Población vs esperanza de vida (año 1997)",
       caption = "Autor: Javier Álvarez Liébana | Datos: gapminder")

Podemos hacer lo mismo pero separando, por ejemplo, por años, con el fichero original sin filtrar.

ggplot(gapminder, aes(y = lifeExp, x = pop,
                      size = gdpPercap, color = continent)) +
  geom_point(alpha = 0.6) +
  scale_x_log10() +
  facet_wrap(~ year) +
  scale_color_tableau() +
  labs(x = "Población", y = "Esperanza de vida",
       color = "Continente", size = "Renta per cápita",
       title = "Ejemplo de ggplot2",
       subtitle = "Población vs esperanza de vida (año 1997)",
       caption = "Autor: Javier Álvarez Liébana | Datos: gapminder")

Se sale fuera de esta introducción pero con theme_update() podemos configurar cualquier aspecto del gráfico.

theme_update(
  # Título, subtítulo y caption
  plot.title = element_text(size = 21, face = "bold", color = "#2a475e"),
  plot.subtitle = element_text(size = 11, face = "bold",
                               color = "black"),
  plot.caption = element_text(size = 9, color = "black"),
  # Ejes
  axis.title = element_text(size = 11, color = "grey30"),
  # Líneas de los ejes
  axis.line = element_line(colour = "grey50"),
  # Fondo dentro de la gr?fica sin formato
  rect = element_blank(),
  # Líneas del grid
  panel.grid = element_line(color = "#b4aea9"),
  # Sin grid secuendario (intermedio entre el grande)
  panel.grid.minor = element_blank(),
  # Grid principal
  panel.grid.major.x =  element_line(linetype = "dashed"),
  panel.grid.major.y = element_line(linetype = "dashed"),
  # Color de fondo
  plot.background =
    element_rect(fill = "#fbf9f4", color = "#fbf9f4"),
  plot.margin = # m?rgenes
      margin(t = 0.3, b = 0.3, r = 0.5, l = 0.5, "cm"))

ggplot(gapminder_1997, aes(y = lifeExp, x = pop,
                           color = continent, size = gdpPercap)) +
  geom_point(alpha = 0.9) +
  scale_x_log10() +
  scale_color_tableau() +
  labs(x = "Población", y = "Esperanza de vida",
       color = "Continent", size = "Renta per cápita",
       title = "Ejemplo de ggplot2",
       subtitle = "Aprendiendo R sin morir en el intento",
       caption = "Autor: Javier Álvarez Liébana | Datos: gapminder")

16.5 Recursos para seguir

Ahora que ya sabes lo básico para poder empezar a trabajar en un entorno amigable, aunque la idea es que este manual tenga más capítulos (¿los tiene?) para seguir avanzando, por si se me olvida, te dejo una lista de recursos útiles para que puedas ir viendo el abanico de opciones que tienes

  • Código de este manual: este manual está programado en sí mismo en R y los códigos pueden ser consultados libremente en el repositorio de GitHub.

  • Visualización de datos en Twitter: una de las fortalezas de R es su versatilidad para la visualización de datos. Y al igual que un escritor necesita leer mucho para tomar ideas, hay dos recursos en Twitter que te recomiendo encarecidamente:
    • El hashtag #TidyTuesday es una etiqueta en la que cada semana se plantea el reto de proponer la mejor visualización para un conjunto de datos dado, donde no solo puedes participar con la comunidad sino ver las visualizaciones de otros usuarios de R.
    • Además he elaborado una lista de Twitter de usuarios que se dedican a la visualización de datos.
  • Datacamp: compendio de cursos que si superas te dan un certificado y sales con un control muy muy potente de data science en R. Son ejercicios sencillos que se van complicando, y la plataforma funciona con tarifa plana: como un netflix de cursos.

  • Generación de informes desde R: el paquete rmarkdown permite generar directamente informes que mezclen texto, fórmulas matemáticas, gráficas y código R (como este mismo manual), sin necesidad de importarlos a otras herramientas de Office.

  • Webs en bookdown. También se puede crear apps/webs interactivas con código R, permitiendo que el usuario selecciona parámetros y se ejecuta código gráficas: ver https://shiny.rstudio.com/tutorial/. Un ejemplo es la web de visualización covid de Asturias que elaboré durante la pandemia para el Gobierno de Asturias (la web en sí está elaborada con shiny, un paquete de R que permite crear aplicaciones web).

  • Comunidad de R hispano: tenemos un grupo de Discord y grupo de Telegram varios usuarios de R en España para compartir recursos.