Requisitos

  • Data:
    • “Licenciamiento institucional_5.xlsx”
    • “tabla1.csv”
    • “tabla2.csv”
    • “tabla3.csv”
    • “tabla4a.csv”
    • “tabla4b.csv”
    • “sida_mujeres_peru.csv”
    • “fallecidos_covid.csv”

Objetivo de la sesión

En esta sesión aprenderás una manera consistente para organizar tus datos en R a la que llamaremos tidy data (datos ordenados).

Llevar tus datos a este formato requiere algo de trabajo previo; sin embargo, dicho trabajo tiene ventajas en el largo plazo. Una vez que tengas tus datos ordenados y las herramientas para ordenar datos que provee el tidyverse, vas a gastar mucho menos tiempo pasando de una forma de representar datos a otra, lo que te permitirá destinar más tiempo a las preguntas analíticas.

Repaso de dplyr y pipes

Actividades

  1. Crear un nuevo proyecto en nuevo directorio: “repaso-pipes”
  2. Crear un nuevo archivo R Markdown:
    • Documento HTML
    • Título: “Repaso de pipes”
    • Contenido: Resolver las preguntas
  3. Presentar el resultado de hacerle Knit al documento.

Escenario

Cierta agencia de financiamiento está interesada en invertir en el sector educativo peruano, específicamente, en el sector universitario. Ingresaron a la Plataforma Nacional de Datos Abiertos y encontraron el set de datos “Licenciamiento Institucional_5.xls” elaborado por SUNEDU.

Te encargan elaborar un pequeño reporte que les resuelva dudas muy puntuales. Además de las respuestas, la agencia está interesada en conocer el código que usaste para obtener los resultados.

Debes responder las siguientes preguntas:

  1. ¿Cuántas universidades públicas y privadas existían en el país cuando se inició el proceso de licenciamiento institucional de universidades peruanas?
  2. ¿Cuántas universidades públicas obtuvieron el licenciamiento?
  3. ¿Cuántas universidades privadas obtuvieron el licenciamiento?
  4. ¿Cuáles son los 5 departamentos con mayor número de universidades licenciadas?

Las respuestas deben ser redactadas en uno o varios párrafos de texto. No basta con generar las tablas o gráficos.

Tidy data (datos ordenados)

“Todas las familias felices se parecen unas a otras, pero cada familia infeliz lo es a su manera.” –– León Tolstoy

“Todos los set de datos ordenados se parecen unos a otros, pero cada set de datos desordenado lo es a su manera” — Hadley Wickham

Esta sesión te dará una introducción práctica a los datos ordenados (o tidy data) y a las herramientas que provee el paquete tidyr. Si deseas aprender más acerca de la teoría subyacente, puede que te guste el artículo Tidy Data publicado en la revista Journal of Statistical Software.

Descarga: http://www.jstatsoft.org/v59/i10/paper

Puedes representar los mismos datos subyacentes de múltiples formas. El ejemplo a continuación muestra los mismos datos organizados de cuatro maneras distintas. Cada set de datos muestra los mismos valores de cuatro variables country, year, cases, population, pero cada uno organiza los valores de forma distinta.

tabla1
## # A tibble: 6 x 4
##   country      year  cases population
##   <chr>       <dbl>  <dbl>      <dbl>
## 1 Afghanistan  1999    745   19987071
## 2 Afghanistan  2000   2666   20595360
## 3 Brazil       1999  37737  172006362
## 4 Brazil       2000  80488  174504898
## 5 China        1999 212258 1272915272
## 6 China        2000 213766 1280428583

tabla2
## # A tibble: 12 x 4
##    country      year type            count
##    <chr>       <dbl> <chr>           <dbl>
##  1 Afghanistan  1999 cases             745
##  2 Afghanistan  1999 population   19987071
##  3 Afghanistan  2000 cases            2666
##  4 Afghanistan  2000 population   20595360
##  5 Brazil       1999 cases           37737
##  6 Brazil       1999 population  172006362
##  7 Brazil       2000 cases           80488
##  8 Brazil       2000 population  174504898
##  9 China        1999 cases          212258
## 10 China        1999 population 1272915272
## 11 China        2000 cases          213766
## 12 China        2000 population 1280428583

tabla3
## # A tibble: 6 x 3
##   country      year rate             
##   <chr>       <dbl> <chr>            
## 1 Afghanistan  1999 745/19987071     
## 2 Afghanistan  2000 2666/20595360    
## 3 Brazil       1999 37737/172006362  
## 4 Brazil       2000 80488/174504898  
## 5 China        1999 212258/1272915272
## 6 China        2000 213766/1280428583

tabla4a
## # A tibble: 3 x 3
##   country     `1999` `2000`
##   <chr>        <dbl>  <dbl>
## 1 Afghanistan    745   2666
## 2 Brazil       37737  80488
## 3 China       212258 213766
tabla4b
## # A tibble: 3 x 3
##   country         `1999`     `2000`
##   <chr>            <dbl>      <dbl>
## 1 Afghanistan   19987071   20595360
## 2 Brazil       172006362  174504898
## 3 China       1272915272 1280428583

Las anteriores son representaciones de los mismos datos subyacentes, pero no todas son igualmente fáciles de usar. Un tipo de conjunto de datos, el conjunto de datos tidy (ordenado) será mucho más fácil de trabajar dentro del tidyverse.

Reglas de tidy data

Existen tres reglas interrelacionadas que hacen que un conjunto de datos sea ordenado:

  1. Cada variable debe tener su propia columna.
  2. Cada observación debe tener su propia fila.
  3. Cada valor debe tener su propia celda.

Estas reglas están interrelacionadas ya que es imposible cumplir solo dos de las tres. Esta interrelación lleva a un conjunto práctico de instrucciones más simple aún:

  • Coloca cada conjunto de datos en un tibble.
  • Coloca cada variable en una columna.

En este ejemplo, solo la tabla1 es tidy. Es la única representación en que cada columna es una variable.

¿Por qué asegurarse de que los datos estén ordenados? Existen dos ventajas principales:

  • Existe una ventaja general al elegir una forma consistente de almacenar datos. Si tienes una estructura de datos consistente, es más fácil aprender las herramientas que funcionan con ella ya que tienen una uniformidad subyacente.

  • Existe una ventaja específica al situar las variables en las columnas, ya que permite que la naturaleza vectorizada de R brille. Muchas de las funciones que vienen con R trabajan con vectores de valores. Esto hace que transformar datos ordenados se perciba como algo casi natural.

dplyr, ggplot2 y el resto de los paquetes del tidyverse están diseñados para trabajar con datos ordenados. Aquí hay algunos ejemplos de cómo podrías trabajar con tabla1.

# Calcular tasa por cada 10,000 habitantes
tabla1 %>%
  mutate(tasa = cases / population * 10000)
## # A tibble: 6 x 5
##   country      year  cases population  tasa
##   <chr>       <dbl>  <dbl>      <dbl> <dbl>
## 1 Afghanistan  1999    745   19987071 0.373
## 2 Afghanistan  2000   2666   20595360 1.29 
## 3 Brazil       1999  37737  172006362 2.19 
## 4 Brazil       2000  80488  174504898 4.61 
## 5 China        1999 212258 1272915272 1.67 
## 6 China        2000 213766 1280428583 1.67

# Calcular casos por año
tabla1 %>%
    group_by(year) %>% 
    summarise(cases = sum(cases)) %>% 
    ungroup()
## # A tibble: 2 x 2
##    year  cases
##   <dbl>  <dbl>
## 1  1999 250740
## 2  2000 296920

# Visualizar cambios en el tiempo
library(ggplot2)
ggplot(tabla1, aes(year, cases)) +
  geom_line(aes(group = country), colour = "grey50") +
  geom_point(aes(colour = country))

Pivotar

Los principios sobre datos ordenados parecen tan obvios que te podrías preguntar si alguna vez encontrarás un set de datos que no esté ordenado. Desafortunadamente, gran parte de los datos que vas a encontrar están desordenados. Existen dos principales razones para esto:

  1. La mayoría de las personas no están familiarizadas con los principios de datos ordenados y es difícil derivarlos por cuenta propia a menos que pases mucho tiempo trabajando con datos.
  2. Los datos a menudo están organizados para facilitar tareas distintas del análisis. Por ejemplo, los datos se organizan para que su registro sea lo más sencillo posible.

Esto significa que para la mayoría de los análisis necesitarás hacer algún tipo de orden. El primer paso es entender siempre cuáles son las variables y las observaciones. ¿Qué es lo que está midiendo el set de datos? Esto a veces es fácil; otras veces deberás consultar con quienes crearon el set de datos.

El segundo paso es resolver uno de los siguientes problemas frecuentes:

  1. Una variable se extiende por varias columnas
  2. Una observación está dispersa entre múltiples filas.

Típicamente, un set de datos tiene uno de estos problemas. Si contiene ambos ¡significa que tienes muy mala suerte!

Para solucionar estos problemas necesitarás las dos funciones más importantes de tidyr:

  • pivot_longer() (pivotar a lo largo), y
  • pivot_wider() (pivotar a lo ancho).

Datos “largos”

Un problema común es cuando en un dataset los nombres de las columnas no representan nombres de variables, sino que representan los valores de una variable. Tomando el caso de la tabla4a: los nombres de las columnas 1999 y 2000 representan los valores de la variable year, los valores en las columnas 1999 y 2000 representan valores de la variable cases y cada fila representa dos observaciones en lugar de una.

tabla4a
## # A tibble: 3 x 3
##   country     `1999` `2000`
##   <chr>        <dbl>  <dbl>
## 1 Afghanistan    745   2666
## 2 Brazil       37737  80488
## 3 China       212258 213766

Para ordenar un dataset como este necesitamos pivotar las columnas que no se ajustan, en un nuevo par de variables. Para describir dicha operación necesitamos tres parámetros:

  • El conjunto de columnas cuyos nombres son valores y no variables. En este ejemplo son las columnas 1999 y 2000.
  • El nombre de la variable al que moveremos los nombres de las columnas. En este caso es year
  • El nombre de la variable al que moveremos los valores de las columnas. En este caso cases

Con estos parámetros podemos utilizar la función pivot_longer() (pivotar a lo largo):

table4a %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "cases")
## # A tibble: 6 x 3
##   country     year   cases
##   <chr>       <chr>  <int>
## 1 Afghanistan 1999     745
## 2 Afghanistan 2000    2666
## 3 Brazil      1999   37737
## 4 Brazil      2000   80488
## 5 China       1999  212258
## 6 China       2000  213766

Las columnas a pivotar quedan seleccionadas siguiendo el estilo de notación de dplyr::select(). En este caso hay solo dos columnas, por lo que las listamos individualmente. Ten en consideración que “1999” y “2000” son nombres no-sintáxicos (debido a que no comienzan con una letra) por lo que los rodeamos con acentos graves (o backticks).

Las variables “year” y “cases” no existen todavía en la tabla4a, por lo que tenemos que poner sus nombres entre comillas.

En el resultado final, las columnas pivotadas se eliminan y obtenemos la nuevas columnas year y cases. La relación entre las variables originales se mantiene, tal como se puede observar en la imagen anterior.

Podemos usar pivot_longer() para ordenar tabla4b de modo similar. La única diferencia es la variable almacenada en los valores de las celdas.

table4b %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "population")
## # A tibble: 6 x 3
##   country     year  population
##   <chr>       <chr>      <int>
## 1 Afghanistan 1999    19987071
## 2 Afghanistan 2000    20595360
## 3 Brazil      1999   172006362
## 4 Brazil      2000   174504898
## 5 China       1999  1272915272
## 6 China       2000  1280428583

Para combinar las versiones ordenadas de tabla4a y tabla4b en un único tibble, necesitamos usar dplyr::left_join(), función necesaria para trabajar con datos relacionales.

tidy4a <- table4a %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "cases")
tidy4b <- table4b %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "population")

left_join(tidy4a, tidy4b)
## # A tibble: 6 x 4
##   country     year   cases population
##   <chr>       <chr>  <int>      <int>
## 1 Afghanistan 1999     745   19987071
## 2 Afghanistan 2000    2666   20595360
## 3 Brazil      1999   37737  172006362
## 4 Brazil      2000   80488  174504898
## 5 China       1999  212258 1272915272
## 6 China       2000  213766 1280428583

Datos “anchos”

pivot_wider() (pivotar a lo ancho) es lo opuesto de pivot_longer(). Se usa cuando una observación aparece en múltiples filas. Por ejemplo, considera la tabla2: una observación es un país en un año, pero cada observación aparece en dos filas.

tabla2
## # A tibble: 12 x 4
##    country      year type            count
##    <chr>       <dbl> <chr>           <dbl>
##  1 Afghanistan  1999 cases             745
##  2 Afghanistan  1999 population   19987071
##  3 Afghanistan  2000 cases            2666
##  4 Afghanistan  2000 population   20595360
##  5 Brazil       1999 cases           37737
##  6 Brazil       1999 population  172006362
##  7 Brazil       2000 cases           80488
##  8 Brazil       2000 population  174504898
##  9 China        1999 cases          212258
## 10 China        1999 population 1272915272
## 11 China        2000 cases          213766
## 12 China        2000 population 1280428583

Para ordenar esto, primero analizamos la representación de un modo similar a cómo se haría con pivot_longer(). Esta vez, sin embargo, necesitamos únicamente dos parámetros:

  • La columna desde la que obtener los nombres de las variables. En este caso corresponde a type.
  • La columna desde la que obtener los valores. En este caso corresponde a count.

Una vez resuelto esto, podemos usar pivot_wider(), como se muestra debajo.

table2 %>%
    pivot_wider(names_from = type, values_from = count)
## # A tibble: 6 x 4
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 1 Afghanistan  1999    745   19987071
## 2 Afghanistan  2000   2666   20595360
## 3 Brazil       1999  37737  172006362
## 4 Brazil       2000  80488  174504898
## 5 China        1999 212258 1272915272
## 6 China        2000 213766 1280428583

Veámoslo gráficamente:

table2 %>%
    pivot_wider(names_from = type, values_from = count)

Como te habrás dado cuenta a partir de sus nombres, las funciones pivot_longer() y pivot_wider() son complementarias. pivot_longer() genera tablas angostas y largas, pivot_wider() genera tablas anchas y cortas.

Separar y unir

Hasta ahora has aprendido a ordenar las tablas tabla2 y tabla4, pero no la tabla3, que tiene un problema diferente: tenemos una columna (rate) que contiene dos variables (casos y población).

Para solucionar este problema, necesitamos la función separate() (separar). También aprenderás acerca del complemento de separate(): unite() (unir), que se usa cuando una única variable se reparte en varias columnas.

Separar

separate() desarma una columna en varias columnas, dividiendo de acuerdo a la posición de un carácter separador. Tomemos la tabla3:

tabla3
## # A tibble: 6 x 3
##   country      year rate             
##   <chr>       <dbl> <chr>            
## 1 Afghanistan  1999 745/19987071     
## 2 Afghanistan  2000 2666/20595360    
## 3 Brazil       1999 37737/172006362  
## 4 Brazil       2000 80488/174504898  
## 5 China        1999 212258/1272915272
## 6 China        2000 213766/1280428583

La columna rate contiene tanto los casos como la población, por lo que necesitamos dividirla en dos variables. La función separate()toma el nombre de la columna a separar y el nombre de las columnas a donde irá el resultado, tal como se muestra en el código a continuación.

table3 %>% 
  separate(rate, into = c("cases", "population"))
## # A tibble: 6 x 4
##   country      year cases  population
##   <chr>       <int> <chr>  <chr>     
## 1 Afghanistan  1999 745    19987071  
## 2 Afghanistan  2000 2666   20595360  
## 3 Brazil       1999 37737  172006362 
## 4 Brazil       2000 80488  174504898 
## 5 China        1999 212258 1272915272
## 6 China        2000 213766 1280428583

Podemos representarlo así:

Por defecto, separate() dividirá una columna donde encuentre un carácter no alfanumérico (esto es, un carácter que no es un número o letra). Por ejemplo, en el siguiente código, separate() divide los valores de rate donde aparece una barra (/). Si deseas usar un carácter específico para separar una columna, puedes especificarlo en el argumento sep de separate().

Por ejemplo, el código anterior se puede re-escribir del siguiente modo:

table3 %>% 
  separate(rate, into = c("cases", "population"), sep = "/")
## # A tibble: 6 x 4
##   country      year cases  population
##   <chr>       <int> <chr>  <chr>     
## 1 Afghanistan  1999 745    19987071  
## 2 Afghanistan  2000 2666   20595360  
## 3 Brazil       1999 37737  172006362 
## 4 Brazil       2000 80488  174504898 
## 5 China        1999 212258 1272915272
## 6 China        2000 213766 1280428583

Mira atentamente los tipos de columna: notarás que cases y population son columnas de tipo carácter. Este es el comportamiento por defecto en separate(): preserva el tipo de columna. Aquí, sin embargo, no es muy útil, ya que se trata de números. Podemos pedir a separate() que intente convertir a un tipo más adecuado usando convert = TRUE:

table3 %>% 
  separate(rate, into = c("cases", "population"), convert = TRUE)
## # A tibble: 6 x 4
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 1 Afghanistan  1999    745   19987071
## 2 Afghanistan  2000   2666   20595360
## 3 Brazil       1999  37737  172006362
## 4 Brazil       2000  80488  174504898
## 5 China        1999 212258 1272915272
## 6 China        2000 213766 1280428583

Unir

unite() es el inverso de separate(): combina múltiples columnas en una única columna. Necesitarás esta función con mucha menos frecuencia que separate(), pero aún así es una buena herramienta para conocer.

Podemos usar unite() para volver a unir las columnas que acabamos de separar.

Usamos col = rate para indicar que la nueva columna debe llamarse rate.

tabla1 %>% 
  unite(col = rate, cases, population, sep = "/")
## # A tibble: 6 x 3
##   country      year rate             
##   <chr>       <dbl> <chr>            
## 1 Afghanistan  1999 745/19987071     
## 2 Afghanistan  2000 2666/20595360    
## 3 Brazil       1999 37737/172006362  
## 4 Brazil       2000 80488/174504898  
## 5 China        1999 212258/1272915272
## 6 China        2000 213766/1280428583

Ejercicios

Usando el set de datos “sida_mujeres_peru.csv”:

  • Convertir el dataset a un formato tidy

Usando el set de datos “fallecidos_covid.csv”

  • Obtener el recuento de fallecidos que nacieron en 1960.

El trabajo debe hacerse en un nuevo proyecto: “ejercicios-tidy”. Pueden estar incluidos en el mismo documento R Markdown.

Unir conjuntos de datos

Existirán ocasiones en que nuestros datos no vengan todos en un solo archivo. Para ello, es necesario aprender tres maneras en que típicamente vamos a necesitar unirlos o combinarlos.

Por filas

Veamos el caso de estos dos df. Contienen información de todos los países de un continente en gapminder.

gapminder_africa <- read_csv("data/gapminder_africa.csv")
gapminder_asia <- read_csv("data/gapminder_asia.csv")

gapminder_africa
## # A tibble: 624 x 6
##    country continent  year lifeExp      pop gdpPercap
##    <chr>   <chr>     <dbl>   <dbl>    <dbl>     <dbl>
##  1 Algeria Africa     1952    43.1  9279525     2449.
##  2 Algeria Africa     1957    45.7 10270856     3014.
##  3 Algeria Africa     1962    48.3 11000948     2551.
##  4 Algeria Africa     1967    51.4 12760499     3247.
##  5 Algeria Africa     1972    54.5 14760787     4183.
##  6 Algeria Africa     1977    58.0 17152804     4910.
##  7 Algeria Africa     1982    61.4 20033753     5745.
##  8 Algeria Africa     1987    65.8 23254956     5681.
##  9 Algeria Africa     1992    67.7 26298373     5023.
## 10 Algeria Africa     1997    69.2 29072015     4797.
## # ... with 614 more rows

gapminder_asia
## # A tibble: 396 x 6
##    country     continent  year lifeExp      pop gdpPercap
##    <chr>       <chr>     <dbl>   <dbl>    <dbl>     <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 386 more rows

En este caso, podemos juntar información de ambos continentes usando bind_rows(), donde cada df a combinar pasa a ser un argumento de la función.

bind_rows(gapminder_africa, gapminder_asia)
## # A tibble: 1,020 x 6
##    country continent  year lifeExp      pop gdpPercap
##    <chr>   <chr>     <dbl>   <dbl>    <dbl>     <dbl>
##  1 Algeria Africa     1952    43.1  9279525     2449.
##  2 Algeria Africa     1957    45.7 10270856     3014.
##  3 Algeria Africa     1962    48.3 11000948     2551.
##  4 Algeria Africa     1967    51.4 12760499     3247.
##  5 Algeria Africa     1972    54.5 14760787     4183.
##  6 Algeria Africa     1977    58.0 17152804     4910.
##  7 Algeria Africa     1982    61.4 20033753     5745.
##  8 Algeria Africa     1987    65.8 23254956     5681.
##  9 Algeria Africa     1992    67.7 26298373     5023.
## 10 Algeria Africa     1997    69.2 29072015     4797.
## # ... with 1,010 more rows

También se puede usar pipes.

gapminder_africa %>% 
    bind_rows(gapminder_asia)
## # A tibble: 1,020 x 6
##    country continent  year lifeExp      pop gdpPercap
##    <chr>   <chr>     <dbl>   <dbl>    <dbl>     <dbl>
##  1 Algeria Africa     1952    43.1  9279525     2449.
##  2 Algeria Africa     1957    45.7 10270856     3014.
##  3 Algeria Africa     1962    48.3 11000948     2551.
##  4 Algeria Africa     1967    51.4 12760499     3247.
##  5 Algeria Africa     1972    54.5 14760787     4183.
##  6 Algeria Africa     1977    58.0 17152804     4910.
##  7 Algeria Africa     1982    61.4 20033753     5745.
##  8 Algeria Africa     1987    65.8 23254956     5681.
##  9 Algeria Africa     1992    67.7 26298373     5023.
## 10 Algeria Africa     1997    69.2 29072015     4797.
## # ... with 1,010 more rows

Ejercicio

Une todos los gapminder continentales en un solo gapminder

Por columnas

Puede darse el caso de que nuestra información tiene las columnas divididas en distintos archivos.

gapminder_parte1 <- gapminder %>% 
    select(country, continent, year)

gapminder_parte2 <- gapminder %>% 
    select(lifeExp, pop, gdpPercap)

gapminder_parte1
## # A tibble: 1,704 x 3
##    country     continent  year
##    <chr>       <chr>     <dbl>
##  1 Afghanistan Asia       1952
##  2 Afghanistan Asia       1957
##  3 Afghanistan Asia       1962
##  4 Afghanistan Asia       1967
##  5 Afghanistan Asia       1972
##  6 Afghanistan Asia       1977
##  7 Afghanistan Asia       1982
##  8 Afghanistan Asia       1987
##  9 Afghanistan Asia       1992
## 10 Afghanistan Asia       1997
## # ... with 1,694 more rows

gapminder_parte2
## # A tibble: 1,704 x 3
##    lifeExp      pop gdpPercap
##      <dbl>    <dbl>     <dbl>
##  1    28.8  8425333      779.
##  2    30.3  9240934      821.
##  3    32.0 10267083      853.
##  4    34.0 11537966      836.
##  5    36.1 13079460      740.
##  6    38.4 14880372      786.
##  7    39.9 12881816      978.
##  8    40.8 13867957      852.
##  9    41.7 16317921      649.
## 10    41.8 22227415      635.
## # ... with 1,694 more rows

En este caso, en lugar de unir los df por filas, las unimos por columnas usando bind_cols()

bind_cols(gapminder_parte1, gapminder_parte2)
## # A tibble: 1,704 x 6
##    country     continent  year lifeExp      pop gdpPercap
##    <chr>       <chr>     <dbl>   <dbl>    <dbl>     <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

Nuevamente, se puede usar pipes.

gapminder_parte1 %>% 
    bind_cols(gapminder_parte2)
## # A tibble: 1,704 x 6
##    country     continent  year lifeExp      pop gdpPercap
##    <chr>       <chr>     <dbl>   <dbl>    <dbl>     <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

Sin embargo, debes tener cuidado al usar bind_cols(), ya que unirá las columnas sin importar si el orden en una de las tablas corresponde al mismo orden de la otra.

Existe una mejor manera de combinar tablas por columnas, haciendo uso de datos relacionales.

Datos relacionales

Imagina que sólo tuviéramos una tabla con la información que corresponde a los 142 países y su continente. La tenemos ordenada por orden alfabético de continente y país.

(gapminder_paises <- read_csv("data/gapminder_paises.csv"))
## # A tibble: 142 x 2
##    country                  continent
##    <chr>                    <chr>    
##  1 Algeria                  Africa   
##  2 Angola                   Africa   
##  3 Benin                    Africa   
##  4 Botswana                 Africa   
##  5 Burkina Faso             Africa   
##  6 Burundi                  Africa   
##  7 Cameroon                 Africa   
##  8 Central African Republic Africa   
##  9 Chad                     Africa   
## 10 Comoros                  Africa   
## # ... with 132 more rows

Sin embargo, en otra tabla tenemos información de expectativa de vida de los países para todos los años que cubre gapminder. Nota que además esta información está ordenada según expectativa de vida de manera descendente.

(gapminder_life <- read_csv("data/gapminder_life.csv"))
## # A tibble: 1,704 x 3
##    country           year lifeExp
##    <chr>            <dbl>   <dbl>
##  1 Japan             2007    82.6
##  2 Hong Kong, China  2007    82.2
##  3 Japan             2002    82  
##  4 Iceland           2007    81.8
##  5 Switzerland       2007    81.7
##  6 Hong Kong, China  2002    81.5
##  7 Australia         2007    81.2
##  8 Spain             2007    80.9
##  9 Sweden            2007    80.9
## 10 Israel            2007    80.7
## # ... with 1,694 more rows

Si quisiéramos obtener el continente de cada uno de los países presente en gapminder_life, sabemos que podemos deducirla del nombre del país guiándonos del contenido de gapminder_paises. La función left_join() nos puede ayudar a realizarlo.

(gapminder_life_paises <- left_join(gapminder_life, gapminder_paises))
## Joining, by = "country"
## # A tibble: 1,704 x 4
##    country           year lifeExp continent
##    <chr>            <dbl>   <dbl> <chr>    
##  1 Japan             2007    82.6 Asia     
##  2 Hong Kong, China  2007    82.2 Asia     
##  3 Japan             2002    82   Asia     
##  4 Iceland           2007    81.8 Europe   
##  5 Switzerland       2007    81.7 Europe   
##  6 Hong Kong, China  2002    81.5 Asia     
##  7 Australia         2007    81.2 Oceania  
##  8 Spain             2007    80.9 Europe   
##  9 Sweden            2007    80.9 Europe   
## 10 Israel            2007    80.7 Asia     
## # ... with 1,694 more rows

Vemos que la información de continente para cada uno de los países se ha repetido para cada año. El trabajo de left_join() es repetir en el conjunto de datos primario (el de la izquierda) todos los valores presentes en el set de datos secundario (el de la derecha) para cada variable en común. Es por eso que para cada país fue asignado el continente correspondiente.

Ahora esta tabla ya permite hacer un análisis por continente.

El argumento by

Cuando las variables tienen nombres en común, left_join() usa por defecto todos los nombres de variable en común entre ambas tablas. Como en el ejemplo anterior el único nombre en común era country, fue la única columna usada.

Ese no es el caso para todos los set de datos

gapminder_pop tiene en común con gapminder_life_paises los nombres de variable country, year y lifeExp, sin embargo esta última variable tiene NA en todas sus observaciones.

(gapminder_pop <- read_csv("data/gapminder_pop.csv"))
## # A tibble: 1,704 x 3
##    country      year      pop
##    <chr>       <dbl>    <dbl>
##  1 Afghanistan  1952  8425333
##  2 Afghanistan  1957  9240934
##  3 Afghanistan  1962 10267083
##  4 Afghanistan  1967 11537966
##  5 Afghanistan  1972 13079460
##  6 Afghanistan  1977 14880372
##  7 Afghanistan  1982 12881816
##  8 Afghanistan  1987 13867957
##  9 Afghanistan  1992 16317921
## 10 Afghanistan  1997 22227415
## # ... with 1,694 more rows

Si dejásemos que left_join() determinara por defecto las columnas a usar en el cruce de datos, se nos presentaría un problema.

left_join(gapminder_life_paises, gapminder_pop)
## Joining, by = c("country", "year")
## # A tibble: 1,704 x 5
##    country           year lifeExp continent       pop
##    <chr>            <dbl>   <dbl> <chr>         <dbl>
##  1 Japan             2007    82.6 Asia      127467972
##  2 Hong Kong, China  2007    82.2 Asia        6980412
##  3 Japan             2002    82   Asia      127065841
##  4 Iceland           2007    81.8 Europe       301931
##  5 Switzerland       2007    81.7 Europe      7554661
##  6 Hong Kong, China  2002    81.5 Asia        6762476
##  7 Australia         2007    81.2 Oceania    20434176
##  8 Spain             2007    80.9 Europe     40448191
##  9 Sweden            2007    80.9 Europe      9031088
## 10 Israel            2007    80.7 Asia        6426679
## # ... with 1,694 more rows

A pesar de que los nombres de variables son iguales, las observaciones de esas variables no son las mismas para cada tabla, debido a ello el cruce no permite obtener los valores adecuados para pop. Felizmente, podemos especificar que se utilicen sólo las variables que sí tienen todos los valores en común entre ambas tablas: country y year.

Para ello usamos el argumento by.

( gapminder_life_pop <- left_join(gapminder_life_paises, gapminder_pop, 
                                by = c("country", "year")) )
## # A tibble: 1,704 x 5
##    country           year lifeExp continent       pop
##    <chr>            <dbl>   <dbl> <chr>         <dbl>
##  1 Japan             2007    82.6 Asia      127467972
##  2 Hong Kong, China  2007    82.2 Asia        6980412
##  3 Japan             2002    82   Asia      127065841
##  4 Iceland           2007    81.8 Europe       301931
##  5 Switzerland       2007    81.7 Europe      7554661
##  6 Hong Kong, China  2002    81.5 Asia        6762476
##  7 Australia         2007    81.2 Oceania    20434176
##  8 Spain             2007    80.9 Europe     40448191
##  9 Sweden            2007    80.9 Europe      9031088
## 10 Israel            2007    80.7 Asia        6426679
## # ... with 1,694 more rows

En este caso, sí pudimos obtener la información de pop correspondiente a cada año y país.

Unir por variable con nombres distintos

Puede ser que a pesar de que tengamos la misma información, la variable se llame distinto en la siguiente tabla. Por ejemplo, en gapminder_gdp la variable country se llama pais.

( gapminder_gdp <- read_csv("data/gapminder_gdp.csv") )
## # A tibble: 1,704 x 3
##    pais       year gdpPercap
##    <chr>     <dbl>     <dbl>
##  1 Kuwait     1957   113523.
##  2 Kuwait     1972   109348.
##  3 Kuwait     1952   108382.
##  4 Kuwait     1962    95458.
##  5 Kuwait     1967    80895.
##  6 Kuwait     1977    59265.
##  7 Norway     2007    49357.
##  8 Kuwait     2007    47307.
##  9 Singapore  2007    47143.
## 10 Norway     2002    44684.
## # ... with 1,694 more rows

Si quisiéramos unir esta información con gapminder_life_pop, sólo year sería reconocida como llave por defecto. Toda la información de gapminder gdp se repetiría para cada año presente.

left_join(gapminder_life_pop, gapminder_gdp)
## # A tibble: 241,968 x 7
##    country  year lifeExp continent       pop pais             gdpPercap
##    <chr>   <dbl>   <dbl> <chr>         <dbl> <chr>                <dbl>
##  1 Japan    2007    82.6 Asia      127467972 Norway              49357.
##  2 Japan    2007    82.6 Asia      127467972 Kuwait              47307.
##  3 Japan    2007    82.6 Asia      127467972 Singapore           47143.
##  4 Japan    2007    82.6 Asia      127467972 United States       42952.
##  5 Japan    2007    82.6 Asia      127467972 Ireland             40676.
##  6 Japan    2007    82.6 Asia      127467972 Hong Kong, China    39725.
##  7 Japan    2007    82.6 Asia      127467972 Switzerland         37506.
##  8 Japan    2007    82.6 Asia      127467972 Netherlands         36798.
##  9 Japan    2007    82.6 Asia      127467972 Canada              36319.
## 10 Japan    2007    82.6 Asia      127467972 Iceland             36181.
## # ... with 241,958 more rows

Tampoco podemos indicarle el nombre de la variable country o pais, porque no existe al mismo tiempo en ambos conjuntos de datos.

left_join(gapminder_life_pop, gapminder_gdp, by = c("country", "year"))
## Error: Join columns must be present in data.
## x Problem with `country`.
left_join(gapminder_life_pop, gapminder_gdp, by = c("pais", "year"))
## Error: Join columns must be present in data.
## x Problem with `pais`.

Necesitamos especificar que la variable de la izquierda equivale con un nombre distinto de la derecha. Seguimos usando el argumento by.

left_join(gapminder_life_pop, gapminder_gdp, by = c("country" = "pais", "year"))
## # A tibble: 1,704 x 6
##    country           year lifeExp continent       pop gdpPercap
##    <chr>            <dbl>   <dbl> <chr>         <dbl>     <dbl>
##  1 Japan             2007    82.6 Asia      127467972    31656.
##  2 Hong Kong, China  2007    82.2 Asia        6980412    39725.
##  3 Japan             2002    82   Asia      127065841    28605.
##  4 Iceland           2007    81.8 Europe       301931    36181.
##  5 Switzerland       2007    81.7 Europe      7554661    37506.
##  6 Hong Kong, China  2002    81.5 Asia        6762476    30209.
##  7 Australia         2007    81.2 Oceania    20434176    34435.
##  8 Spain             2007    80.9 Europe     40448191    28821.
##  9 Sweden            2007    80.9 Europe      9031088    33860.
## 10 Israel            2007    80.7 Asia        6426679    25523.
## # ... with 1,694 more rows