class: left, middle, title-slide .title[ # Elementos DS ] .subtitle[ ## 04 Manipulación de datos
dplyr tidyr
] .author[ ###
Joshua Kunst
@jbkunst
] .date[ ### 2022-06-01 ] --- class: inverse center middle # Datos ordenados --- ## Datos ordenados En este capítulo 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 retorno positivo 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. Lo anterior viene de [datos ordenados](https://es.r4ds.hadley.nz/datos-ordenados.html) de R4DS. --- ## Tabla 1 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 dataset muestra los mismos valores de cuatro variables —pais, anio, poblacion y casos (de tuberculosis)—, pero cada uno organiza los valores de forma distinta. ```r library(datos) tabla1 ``` ``` ## # A tibble: 6 × 4 ## pais anio casos poblacion ## <chr> <int> <int> <int> ## 1 Afganistán 1999 745 19987071 ## 2 Afganistán 2000 2666 20595360 ## 3 Brasil 1999 37737 172006362 ## 4 Brasil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` --- ## Tabla 2 Identifiquemos los valores asociados a pais, anio, poblacion y casos. ```r tabla2 ``` ``` ## # A tibble: 12 × 4 ## pais anio tipo cuenta ## <chr> <int> <chr> <int> ## 1 Afganistán 1999 casos 745 ## 2 Afganistán 1999 población 19987071 ## 3 Afganistán 2000 casos 2666 ## 4 Afganistán 2000 población 20595360 ## 5 Brasil 1999 casos 37737 ## 6 Brasil 1999 población 172006362 ## 7 Brasil 2000 casos 80488 ## 8 Brasil 2000 población 174504898 ## 9 China 1999 casos 212258 ## 10 China 1999 población 1272915272 ## 11 China 2000 casos 213766 ## 12 China 2000 población 1280428583 ``` --- ## Tabla 3 Identifiquemos los valores asociados a pais, anio, poblacion y casos. ```r tabla3 ``` ``` ## # A tibble: 6 × 3 ## pais anio tasa ## <chr> <int> <chr> ## 1 Afganistán 1999 745/19987071 ## 2 Afganistán 2000 2666/20595360 ## 3 Brasil 1999 37737/172006362 ## 4 Brasil 2000 80488/174504898 ## 5 China 1999 212258/1272915272 ## 6 China 2000 213766/1280428583 ``` --- ## Tabla 4a y 4b Identifiquemos los valores asociados a pais, anio, poblacion y casos. ```r tabla4a ``` ``` ## # A tibble: 3 × 3 ## pais `1999` `2000` ## <chr> <int> <int> ## 1 Afganistán 745 2666 ## 2 Brasil 37737 80488 ## 3 China 212258 213766 ``` ```r tabla4b ``` ``` ## # A tibble: 3 × 3 ## pais `1999` `2000` ## <chr> <int> <int> ## 1 Afganistán 19987071 20595360 ## 2 Brasil 172006362 174504898 ## 3 China 1272915272 1280428583 ``` --- # Varias representaciones/misma información Las tablas: - `tabla1` - `tabla2` - `tabla3` - `tabla4a` y `tabla4b` Son representaciones de los mismos datos subyacentes, pero no todas son igualmente fáciles de usar. Por ejemplo, revisemos nuevamente las tablas y _obtenga la tasa de tuberculosis para cada país/año_. Un tipo de conjunto de datos, el conjunto de **datos ordenado**, será mucho más fácil de trabajar. --- # Definición Datos ordenados Existen tres reglas interrelacionadas que hacen que un conjunto de datos sea ordenado: - Cada variable debe tener su propia columna. - Cada observación debe tener su propia fila. - Cada valor debe tener su propia celda. <img src="images/tidy-1.svg" width="70%" style="display: block; margin: auto;" /> --- ## Pivotar Como previamente vimos ciertas tablas poseen los siguientes problemas. 1. Una variable se extiende por varias columnas, por ejemplo `tabla4a`. 1. Una observación está dispersa entre múltiples filas, por ejemplo la `tabla2`. Para solucionar estos problemas revisaremos dos funciones del paquete **tidyr** (que viene incluído en el paquet **tidyverse**, asi que cargas solamente este último), que son: - `pivot_longer` que es para pivotar a lo largo. - `pivot_wider` para 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 año, los valores en las columnas `1999` y `2000` representan los valores de la variable casos. Para ordenar un dataset como este necesitamos tres parámetros: - El conjunto de columnas cuyos nombres son valores y no variables. En este ejemplo son las columnas `1999` y `2000`. Argumento `cols` que se refiere a las columnas a trabajar. - El nombre de la variable cuyos valores forman los nombres de las columnas. Argumento `names_to`. - El nombre de la variable cuyos valores están repartidos por las celdas. Argumento `values_to`. Con estos parámetros podemos utilizar la función `pivot_longer()` (pivotar a lo largo). --- count: false ## Ejemplo <code>pivot_longer</code> .panel1-pivot_longer-auto[ ```r *library(tidyverse) ``` ] .panel2-pivot_longer-auto[ ] --- count: false ## Ejemplo <code>pivot_longer</code> .panel1-pivot_longer-auto[ ```r library(tidyverse) *library(datos) ``` ] .panel2-pivot_longer-auto[ ] --- count: false ## Ejemplo <code>pivot_longer</code> .panel1-pivot_longer-auto[ ```r library(tidyverse) library(datos) *tabla4a ``` ] .panel2-pivot_longer-auto[ ``` ## # A tibble: 3 × 3 ## pais `1999` `2000` ## <chr> <int> <int> ## 1 Afganistán 745 2666 ## 2 Brasil 37737 80488 ## 3 China 212258 213766 ``` ] --- count: false ## Ejemplo <code>pivot_longer</code> .panel1-pivot_longer-auto[ ```r library(tidyverse) library(datos) tabla4a |> * pivot_longer( * cols = c(`1999`, `2000`), * names_to = "anio", * values_to = "casos" * ) ``` ] .panel2-pivot_longer-auto[ ``` ## # A tibble: 6 × 3 ## pais anio casos ## <chr> <chr> <int> ## 1 Afganistán 1999 745 ## 2 Afganistán 2000 2666 ## 3 Brasil 1999 37737 ## 4 Brasil 2000 80488 ## 5 China 1999 212258 ## 6 China 2000 213766 ``` ] <style> .panel1-pivot_longer-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel2-pivot_longer-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel3-pivot_longer-auto { color: black; width: NA%; hight: 33%; float: left; padding-left: 1%; font-size: 80% } </style> --- ## 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. 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 tipo, argumento `names_from`. - La columna desde la que obtener los valores. En este caso corresponde a cuenta, argumento `values_from`. Una vez resuelto esto, podemos usar `pivot_wider()`, como se muestra en el siguiente ejemplo. --- count: false ## Ejemplo <code>pivot_wider</code> .panel1-pivot_wider-auto[ ```r *tabla2 ``` ] .panel2-pivot_wider-auto[ ``` ## # A tibble: 12 × 4 ## pais anio tipo cuenta ## <chr> <int> <chr> <int> ## 1 Afganistán 1999 casos 745 ## 2 Afganistán 1999 población 19987071 ## 3 Afganistán 2000 casos 2666 ## 4 Afganistán 2000 población 20595360 ## 5 Brasil 1999 casos 37737 ## 6 Brasil 1999 población 172006362 ## 7 Brasil 2000 casos 80488 ## 8 Brasil 2000 población 174504898 ## 9 China 1999 casos 212258 ## 10 China 1999 población 1272915272 ## 11 China 2000 casos 213766 ## 12 China 2000 población 1280428583 ``` ] --- count: false ## Ejemplo <code>pivot_wider</code> .panel1-pivot_wider-auto[ ```r tabla2 |> * pivot_wider( * names_from = tipo, * values_from = cuenta * ) ``` ] .panel2-pivot_wider-auto[ ``` ## # A tibble: 6 × 4 ## pais anio casos población ## <chr> <int> <int> <int> ## 1 Afganistán 1999 745 19987071 ## 2 Afganistán 2000 2666 20595360 ## 3 Brasil 1999 37737 172006362 ## 4 Brasil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` ] <style> .panel1-pivot_wider-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel2-pivot_wider-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel3-pivot_wider-auto { color: black; width: NA%; hight: 33%; float: left; padding-left: 1%; font-size: 80% } </style> --- count: false ## <code>pivot_longer</code> y <code>pivot_wider</code> no son simétricas .panel1-pivot_longesr_wider_example-auto[ ```r # no son perfectanente simétricas *acciones <- tibble( * anio = c(2015, 2015, 2016, 2016), * semestre = c(1, 2, 1, 2), * retorno = c(1.88, 0.59, 0.92, 0.17) *) ``` ] .panel2-pivot_longesr_wider_example-auto[ ] --- count: false ## <code>pivot_longer</code> y <code>pivot_wider</code> no son simétricas .panel1-pivot_longesr_wider_example-auto[ ```r # no son perfectanente simétricas acciones <- tibble( anio = c(2015, 2015, 2016, 2016), semestre = c(1, 2, 1, 2), retorno = c(1.88, 0.59, 0.92, 0.17) ) *acciones ``` ] .panel2-pivot_longesr_wider_example-auto[ ``` ## # A tibble: 4 × 3 ## anio semestre retorno ## <dbl> <dbl> <dbl> ## 1 2015 1 1.88 ## 2 2015 2 0.59 ## 3 2016 1 0.92 ## 4 2016 2 0.17 ``` ] --- count: false ## <code>pivot_longer</code> y <code>pivot_wider</code> no son simétricas .panel1-pivot_longesr_wider_example-auto[ ```r # no son perfectanente simétricas acciones <- tibble( anio = c(2015, 2015, 2016, 2016), semestre = c(1, 2, 1, 2), retorno = c(1.88, 0.59, 0.92, 0.17) ) acciones %>% * pivot_wider( * names_from = anio, * values_from = retorno * ) ``` ] .panel2-pivot_longesr_wider_example-auto[ ``` ## # A tibble: 2 × 3 ## semestre `2015` `2016` ## <dbl> <dbl> <dbl> ## 1 1 1.88 0.92 ## 2 2 0.59 0.17 ``` ] --- count: false ## <code>pivot_longer</code> y <code>pivot_wider</code> no son simétricas .panel1-pivot_longesr_wider_example-auto[ ```r # no son perfectanente simétricas acciones <- tibble( anio = c(2015, 2015, 2016, 2016), semestre = c(1, 2, 1, 2), retorno = c(1.88, 0.59, 0.92, 0.17) ) acciones %>% pivot_wider( names_from = anio, values_from = retorno ) %>% * pivot_longer( * cols = `2015`:`2016`, * names_to = "anio", * values_to = "retorno" * ) ``` ] .panel2-pivot_longesr_wider_example-auto[ ``` ## # A tibble: 4 × 3 ## semestre anio retorno ## <dbl> <chr> <dbl> ## 1 1 2015 1.88 ## 2 1 2016 0.92 ## 3 2 2015 0.59 ## 4 2 2016 0.17 ``` ] <style> .panel1-pivot_longesr_wider_example-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel2-pivot_longesr_wider_example-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel3-pivot_longesr_wider_example-auto { color: black; width: NA%; hight: 33%; float: left; padding-left: 1%; font-size: 80% } </style> --- ## Separar (y Unir) ¿Qué pasa con `tabla3`? Ésta tiene un ~problema~ característica diferente: una columna contiene dos valores `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. --- count: false ## Ejemplo <code>separate unite</code> .panel1-separate_unite-auto[ ```r *tabla3 ``` ] .panel2-separate_unite-auto[ ``` ## # A tibble: 6 × 3 ## pais anio tasa ## <chr> <int> <chr> ## 1 Afganistán 1999 745/19987071 ## 2 Afganistán 2000 2666/20595360 ## 3 Brasil 1999 37737/172006362 ## 4 Brasil 2000 80488/174504898 ## 5 China 1999 212258/1272915272 ## 6 China 2000 213766/1280428583 ``` ] --- count: false ## Ejemplo <code>separate unite</code> .panel1-separate_unite-auto[ ```r tabla3 %>% * separate( * tasa, * into = c("casos", "poblacion"), * convert = TRUE # convierte al tipo adecuado * ) ``` ] .panel2-separate_unite-auto[ ``` ## # A tibble: 6 × 4 ## pais anio casos poblacion ## <chr> <int> <int> <int> ## 1 Afganistán 1999 745 19987071 ## 2 Afganistán 2000 2666 20595360 ## 3 Brasil 1999 37737 172006362 ## 4 Brasil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` ] --- count: false ## Ejemplo <code>separate unite</code> .panel1-separate_unite-auto[ ```r tabla3 %>% separate( tasa, into = c("casos", "poblacion"), convert = TRUE # convierte al tipo adecuado ) |> * unite( * nueva_tasa, * casos, poblacion, * sep = " dividido " * ) ``` ] .panel2-separate_unite-auto[ ``` ## # A tibble: 6 × 3 ## pais anio nueva_tasa ## <chr> <int> <chr> ## 1 Afganistán 1999 745 dividido 19987071 ## 2 Afganistán 2000 2666 dividido 20595360 ## 3 Brasil 1999 37737 dividido 172006362 ## 4 Brasil 2000 80488 dividido 174504898 ## 5 China 1999 212258 dividido 1272915272 ## 6 China 2000 213766 dividido 1280428583 ``` ] <style> .panel1-separate_unite-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel2-separate_unite-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel3-separate_unite-auto { color: black; width: NA%; hight: 33%; float: left; padding-left: 1%; font-size: 80% } </style> --- # Ejercicios <small>`pivot_wider` / `pivot_longer` / `separate`</small> 1. Para cada una de las tablas, realizar las transformaciones necesarias para obtener la tasa de casos de tuberculosis: - `tabla1` - `tabla2` - `tabla3` - `tabla4a` y `tabla4b` 1. Para `tabla1` graficar la evolución de la tasa para cada país. ¿Qué observa? --- class: inverse center middle # Datos relacionales --- ## Datos relacionales Es raro que un análisis de datos involucre una única tabla de datos. Lo típico es que tengas muchas tablas que debes combinar para responder a tus preguntas de interés. De manera colectiva, se le llama datos relacionales a esas múltiples tablas de datos, ya que sus relaciones, y no solo los conjuntos de datos individuales, son importantes. Las relaciones siempre se definen sobre un par de tablas. Todas las otras relaciones se construyen sobre esta idea simple: las relaciones entre tres o más tablas son siempre una propiedad de las relaciones entre cada par. ¡A veces ambos elementos de un par pueden ser la misma tabla! Esto se necesita si, por ejemplo, tienes una tabla de personas y cada persona tiene una referencia a sus padres. Lo anterior viene de [datos relacionales](https://es.r4ds.hadley.nz/datos-relacionales.html) de R4DS. --- ## Tipos de opearciones entre 2 tablas Existen distintas formas de operar con 2 data frames: - **Uniones de transformación** (del inglés _mutating joins_), que agregan nuevas variables a un data frame a partir de las observaciones coincidentes en otra tabla. - **Uniones de filtro** (del inglés _filtering joins_), que filtran observaciones en un data frame con base en si coinciden o no con una observación de otra tabla. - **Operaciones de conjuntos** (del inglés _set operations_), que tratan las observaciones como elementos de un conjunto. Los _mutating joins_ (en adelante _joins_) serán los más usuales y los que estudiaremos con más detalle. --- ## De forma visual <img src="images/dplyr/joins2.png" width="70%" style="display: block; margin: auto;" /> --- ## Un poco más ejemplificado <img src="images/dplyr/all-dplyr-joins.png" width="70%" style="display: block; margin: auto;" /> --- ## El famoso `left_join` Este es el _join_ más usual dado que **fija** la tabla de la izquierda (**left**) y agrega la información de la tabla derecha. De **forma general** para realizar un _join_ necesitaremos: - Dos tablas. Parámetros `x` e `y`. - Definir que columnas serán las utilizadas para realizar el _match_. En la mayoría de casos es una columna en cada tabla, pero no siempre es así, por ejemplo en ciertos casos se requiere juntar información por _rut_ y _fecha_. Parámetro `by`. (El 2do en popularidad en mi opinión es el `full_join`) --- count: false ## Ejemplo <code>left_join</code> .panel1-left_join-auto[ ```r *library(tidyverse) ``` ] .panel2-left_join-auto[ ] --- count: false ## Ejemplo <code>left_join</code> .panel1-left_join-auto[ ```r library(tidyverse) *band_members ``` ] .panel2-left_join-auto[ ``` ## # A tibble: 3 × 2 ## name band ## <chr> <chr> ## 1 Mick Stones ## 2 John Beatles ## 3 Paul Beatles ``` ] --- count: false ## Ejemplo <code>left_join</code> .panel1-left_join-auto[ ```r library(tidyverse) band_members *band_instruments ``` ] .panel2-left_join-auto[ ``` ## # A tibble: 3 × 2 ## name band ## <chr> <chr> ## 1 Mick Stones ## 2 John Beatles ## 3 Paul Beatles ``` ``` ## # A tibble: 3 × 2 ## name plays ## <chr> <chr> ## 1 John guitar ## 2 Paul bass ## 3 Keith guitar ``` ] --- count: false ## Ejemplo <code>left_join</code> .panel1-left_join-auto[ ```r library(tidyverse) band_members band_instruments *left_join( * band_members, * band_instruments, * by = "name" * ) ``` ] .panel2-left_join-auto[ ``` ## # A tibble: 3 × 2 ## name band ## <chr> <chr> ## 1 Mick Stones ## 2 John Beatles ## 3 Paul Beatles ``` ``` ## # A tibble: 3 × 2 ## name plays ## <chr> <chr> ## 1 John guitar ## 2 Paul bass ## 3 Keith guitar ``` ``` ## # A tibble: 3 × 3 ## name band plays ## <chr> <chr> <chr> ## 1 Mick Stones <NA> ## 2 John Beatles guitar ## 3 Paul Beatles bass ``` ] <style> .panel1-left_join-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel2-left_join-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel3-left_join-auto { color: black; width: NA%; hight: 33%; float: left; padding-left: 1%; font-size: 80% } </style> --- count: false ## Ejemplo <code>full_join</code> .panel1-full_join-auto[ ```r *library(tidyverse) ``` ] .panel2-full_join-auto[ ] --- count: false ## Ejemplo <code>full_join</code> .panel1-full_join-auto[ ```r library(tidyverse) *band_members ``` ] .panel2-full_join-auto[ ``` ## # A tibble: 3 × 2 ## name band ## <chr> <chr> ## 1 Mick Stones ## 2 John Beatles ## 3 Paul Beatles ``` ] --- count: false ## Ejemplo <code>full_join</code> .panel1-full_join-auto[ ```r library(tidyverse) band_members *band_instruments ``` ] .panel2-full_join-auto[ ``` ## # A tibble: 3 × 2 ## name band ## <chr> <chr> ## 1 Mick Stones ## 2 John Beatles ## 3 Paul Beatles ``` ``` ## # A tibble: 3 × 2 ## name plays ## <chr> <chr> ## 1 John guitar ## 2 Paul bass ## 3 Keith guitar ``` ] --- count: false ## Ejemplo <code>full_join</code> .panel1-full_join-auto[ ```r library(tidyverse) band_members band_instruments *full_join( * band_members, * band_instruments, * by = "name" * ) ``` ] .panel2-full_join-auto[ ``` ## # A tibble: 3 × 2 ## name band ## <chr> <chr> ## 1 Mick Stones ## 2 John Beatles ## 3 Paul Beatles ``` ``` ## # A tibble: 3 × 2 ## name plays ## <chr> <chr> ## 1 John guitar ## 2 Paul bass ## 3 Keith guitar ``` ``` ## # A tibble: 4 × 3 ## name band plays ## <chr> <chr> <chr> ## 1 Mick Stones <NA> ## 2 John Beatles guitar ## 3 Paul Beatles bass ## 4 Keith <NA> guitar ``` ] <style> .panel1-full_join-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel2-full_join-auto { color: black; width: 49%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel3-full_join-auto { color: black; width: NA%; hight: 33%; float: left; padding-left: 1%; font-size: 80% } </style> --- ## Ejercicios 1. Considere las tablas `band_members`, `band_instruments` y `band_instruments2`. - Realice un `left_join` entre `band_members`, `band_instruments`. - Realice un `left_join` entre `band_members`, `band_instruments2`. - ¿Cuál es la diferencia? 1. Vuelva a los datos de `vuelos` y `aeropuertos` y grafique en el mapa los segmentos que corresponden a los viajes entre un areopuerto y el otro.