¿Qué hace que un fichero de datos este limpio?

Empezemos con la la carga de la librería de tidyverse. En este modulo se trabajará con la libreria “tidyr” dentro del grupo de librerías “tidyverse”

library(tidyverse)
## -- Attaching packages ----------------------------------------------------------------------------------------------- tidyverse 1.2.1 --
## v ggplot2 3.1.0     v purrr   0.2.5
## v tibble  1.4.2     v dplyr   0.7.8
## v tidyr   0.8.2     v stringr 1.3.1
## v readr   1.1.1     v forcats 0.3.0
## -- Conflicts -------------------------------------------------------------------------------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()

Diferencia entre uno limpio y uno no:

  1. Cada variable debe estar en una columna diferente, no pueden estar mezclados los valores

  2. Cada una de las observaciones han de tener su propia fila

  3. Cada valor debe estar en su propia celda.

Funciones de TIDYR

Spreading y gathering

Problemas que podemos encontrar a la hora de trabajar con una nueva base de datos:

  • ¿Qué es variable y qué es observación? -> mirar las tres normas de limpieza

Para limpiar correctamente un nuevo dataset haremos uso de las funciones de gather() y spread()

La técnica de gathering (reunión)

Gather nos permitirá unificar diferentes variables en una sola columna. Necesita 3 parámetros:

  1. Conjunto de valores que representan valores (no variables)

  2. La clave (key) donde pondremos el nombre de las variables

  3. El valor que usaremos

Este es e dataset que transformaremos:

table4a

Usaremos gather para unificar year en una sola variable:

table4a %>% 
  gather("1999","2000",key = "year", value = "cases") -> tidy4a
tidy4a

Hemos creado un diccionario o array asociativo. Otro ejemplo de limpieza de datos:

table4b

Usamos la función gather:

table4b %>%
  gather("1999","2000", key = "year", value = "population") -> tidy4b
tidy4b

Unificación de los dos data fraes que hemos creados con left_join():

left_join(tidy4a,tidy4b)
## Joining, by = c("country", "year")

La técnica de spreading

La función spread nos sirve para juntar observaciones que estan en diferentes líneas, en una sola. Ejemplo:

table2

Para spread solo necesitamos dos valores, la clave (corresponderá la columna que contemplará el nombre de la variable que quiero separar) y el valor (nombre de la columna que contiene los diferentes valores que quiero separar).

table2 %>%
  spread(key = type, value = count)

La técnica de separación y unificación, separate() y unite()

Análisis de un nuevo data frame:

table3

La columna rate tiene dos variables dentro de ella, y además esta en character. ¿Cómo podemos tratar estos datos? Haremos uso de:

  • separate() -> separa una columna a partir de un valore especificado

  • unite() -> unificación de diferentes valores

separate()

table3 %>%
  separate(rate, into = c("cases","population"), 
           sep = "/", convert = TRUE) # no me hace falta determinar el separador, ya esta de forma interna en separate. Con convert igual a true, le  pedimos que  mire el tipo de  dato que  es para que le de el formato correcto

También podemos separar especificando por la posición para todoas las observaciones. Imaginemos que queremos separar siglo y año:

table3 %>%
  separate(rate, into = c("cases","population"), 
           sep = "/", convert = TRUE) %>%
  separate(year, sep = 2, into = c("century","year"), convert = TRUE)

La técnica de reunión

Usando la tabla5 para rejuntar siglo con año, usaremos la función unite():

table5

Usamos la función unite():

table5 %>%
  unite(new_year, century, year)

El separador por defecto es una “_“, si queremos especificarlo:

table5 %>%
  unite(new_year, century, year, sep = "")

Los NA en la limpieza de los datos

Los NAs solo pueden aparecer en dos formas:

  1. de forma explícita: el dato falta y es “NA”

  2. de forma implícita: el dato no aparecía en el dataset original, antes de ser transformado, o podría ser que en el orginal no hubiera un NA pero al tranformarse fuera un NA.

Primero creamos el dataset con el que vamos a trabajar:

roi <- tibble(
  year = c(rep(2016,4), rep(2017,4), 2018),
  quarter = c(rep(c(1,2,3,4),2),1),
  return = rnorm(9, mean = 0.5, sd = 1)
)
roi

Vamos a hacer aparecer algun NA de forma explícita, no podemos saber que valor debería ir en esta posición, porqué el dato no existe:

roi$return[7] =  NA
roi

En cambio, si eliminamos una fila, podemos decir que hay un NA de algo que debería estar pero no está:

roi %>%
  spread(year, return)

Aquí podemos ver que nos faltan más datos de los localizados a primera vista. ¿Cómo tratarlos?

roi %>%
  spread(year, return) %>%
  gather(year, return, "2016":"2018", na.rm = TRUE)

Aquí hemos tratado los NAs implícitos y explícitos con el parametro na.rm().

La función complete(), completará el conjunto de columnas que hayamos indicado y rellenara de forma explícita con NAs allí donde haga falta.

roi %>%
  complete(year,quarter)

Complete() nos ha mostrado tres NA al final que no estavan introducidos. También se puede hacer uso de la función fill() para rellenar datos.

Datos relacionales con R

Base de datos relacionales -> bases de datos relacionadas a partir de ciertas variables.

Para ver la relación entre diferentas tablas, haremos uso de los datos relacionales de los dataset de la libreria(flights). Los datos relacionados son los siguientes:

datos NYCflights13 relacionados

datos NYCflights13 relacionados

library(nycflights13)

Las claves primarias y foraneas

Una claves es una variable o un conjunto de variables per que de forma unívoca identifica la observación. Existen dos tipos de clave:

  • clave primaria: identifica de forma unívoca un observación de su propia tabla

  • clave foranea: identifica únicament la observación en otra tabla.

Una variable puede ser primaria y foranea.

¿Cómo se que tailnum es la clave primaria del data set planes?

nycflights13::planes %>%
  count(tailnum) %>%
  filter(n>1)

Al ser 0, nos muestra que no hay ningún avión que tenga un número de cola repetido.

¿Cómo se que year, month, day, hour y origin conjuntamente son claves primarias?

weather %>%
  count(year, month, day, hour, origin) %>%
  filter(n>1)

Por lo tanto, son variables foraneas.

En el caso que no tengamos una clave primaria, podríamos añadir una a mano con mutate() o usando el número de la linea.

Los mutating joins

Nos permite combinar variables de dos tablas. Primero buscará observaciones que coincidan por clave, y luego hacer copas a través de las variables de una tabla a la otra.

flights_new <- flights %>%
  select(year:day, hour, origin, dest, tailnum, carrier)
head(flights_new)

Principalmente nos hemos quedado con las claves primarias:

flights_new %>% 
  left_join(airlines, by = "carrier") %>%
  head(10)

Podríamos haber obtenido el mismo resultado usando mutate() para crear una primary key:

head(flights_new) %>%
  mutate(name = airlines$name[match(carrier, airlines$carrier)])

Diagramas para entender los joins

Metodología de los joins

Metodología de los joins

Ejemplo para entender los joins:

x <- tribble(
  ~key, ~value_x,
     1,     "x1",
     2,     "x2",
     3,     "x3"
)

y <- tribble(
  ~key, ~value_y,
     1,     "y1",
     2,     "y2",
     4,     "y3"
)

Inner join

Se esperan que las claves coincidan a la perfeccion entre las claves del primer y el segundo dataframe.

Los inner join

Los inner join

Como realizamos el join a partir de la clave comuna:

x %>%
  inner_join(y, by = "key")

La propiedad más importante de un inner join es que solo es capaz de mantener los resultados que aparecen en ambas tablas.

Outer Join

Outer join

Outer join

El outer join conserva las observaciones que aparecen al menos en una de las dos tablas. Diferentes tipos de outer join:

  • Left join: se queda con todas las observaciones que aparecen en el primer data set independientemente del segundo

  • Right join: se queda con todas las observaciones que aparecen en el segundo data set independientemente del primero

  • Full join: se queda con las observaciones tanto del primero como del segundo data frame.

Existen también otra forma de ver los joins a través de los diagramas de conjuntos:

Diagramas de conjunntos

Diagramas de conjunntos

Vamos a ver diferentes ejemplos:

x %>% inner_join(y, by = "key")
x %>% left_join(y, by = "key")
x %>% right_join(y, by = "key")
x %>% full_join(y, by = "key")

El problema de las claves duplicadas

¿Qué ocurre cuando las claves estan duplicadas?

Claves duplicadas

Claves duplicadas

Creamos la tribble del ejemplo:

x <- tribble(
  ~key, ~value_x,
     1,     "x1",
     2,     "x2",
     2,     "x3",
     1,     "x4"
)

y <- tribble(
  ~key, ~value_y, 
     1,     "y1",
     2,     "y2"
)

Una vez los datasets creados vamos a ver como podemos aplicar el join:

x %>% left_join(y, by = "key")

También puede pasar que hayan claves duplicadas en las dos tablas. Cuando se combinan los dos se juntan todas las posibles combinaciones, creando un producto cartesiano.

claves duplicadas ambas tablas

claves duplicadas ambas tablas

Creación de los tribbles con los que trabajaremos:

x <- tribble(
  ~key, ~value_x,
     1,     "x1",
     2,     "x2",
     2,     "x3",
     3,     "x4"
)

y <- tribble(
  ~key, ~value, 
     1,   "y1",
     2,   "y2",
     2,   "y3",
     3,   "y4"
)

Creemos el left join para este caso,

left_join(x,y, by = "key")

Definir las columnas claves de los joins

Si no se especifican las variables clave par a la unificación de dos datasets, joing cogerá el parametro “NULL” por defecto. Esto quiere decir que buscará todas las variables que coincidan el los dos datasets. Ejemplo:

head(flights_new) %>% left_join(weather)
## Joining, by = c("year", "month", "day", "hour", "origin")

En pantalla mostrará el natural join, como se llama cuando no se especifica el parametro by().

Podemos también hacer un join donde le damos a entender que hay alguna variable que es la misma en dos datasets distintos, pero tienen un nombre diferente:

flights_new %>%
  left_join(airports, by = c("dest" = "faa")) %>%
  head(10)

Unas nociones de SQL y de la función merge

La función merge() tiene la misma función que los join. Ahora mostraremos primero la relación enrte DPLYR y el paquete base de R, y también con SQL(standard query location)

  1.   dplyr     <->   base R
  • inner_join(x,y) <-> merge(x,y)

  • left_join(x,y) <-> merge(x, y, all.x = TRUE)

  • right_join(x,y) <-> merge(x, y, all.y = TRUE)

  • full_join(x,y) <-> merge(x, y, all.x = TRUE, all.y = TRUE)

  1.   dplyr               <->             SQL
  • left_join(x, y, by = “z”)

                                SELECT * FROM x INNER JOIN y USING (z)
    
                                SELECT * FROM x INNER JOIN y ON x.key = y.key
  • left_join(x,y, by = “z”)

                               SELECT * FROM x LEFT OUTER JOIN y USING(z)
    
                               SELECT * FROM x LEFT OUTER JOIN y ON x.key = y.key
  • right_join(x,y, by = “z”)

                               SELECT * FROM x RIGHT OUTER JOIN y USING (z)
    
                               SELECT * FROM x RIGHT OUTER JOIN y ON x.key = y.key
  • full_join(x,y, by = “z”)

                               SELECT * FROM x FULL OUTER JOIN y USING (z)
    
                               SELECT + FROM x FULL OUTER JOIN y ON x.key = y.key

Filtering joins

Junta dataframes afectando a las observaciones no a las variables. Existen dos tipos de filtering joins:

  • semi_join(x,y) -> se queda con las observaciones de x que tienen correspondencia con y

  • anti_join(x,y) -> eliminan todas las observaciones de x que tienen correspondencia en y

Ejemplo del que podemos hacer con filter_join():

flights %>%
  count(dest, sort = TRUE) %>%
  head(10) -> top_dest

Ahora haremos un filtrado de la información, para saber la lista total de los vuelos que volaron en alguno del top 10 destinos:

flights %>%
  filter(dest %in% top_dest$dest)

Hacer el filtrado con semi_join():

flights %>% semi_join(top_dest) %>%
  head(10)
## Joining, by = "dest"

Gráfico de como quedaría un semi_join():

semi_join()

semi_join()

Un anti_join hace el proceso contrario:

anti_join()

anti_join()

Como hacer un anti_join(), encontrar correspondencias o no con diferentes datasets:

flights %>% anti_join(planes, by = "tailnum") %>%
  count(tailnum, sort = TRUE) %>%
  head(10)

Operaciones conjuntísticas, entre dos tablas

Principalmente son 3:

  1. intersect(x,y): observaciones comunes a “x” e “y”

  2. union(x,y): observaciones únicas en “x” e “y”

  3. setdiff(x,y): observaciones en “x” pero no en “y” (x - y)

Ejemplo:

x <- tribble(
  ~a, ~b,
   1,  1,
   2,  1
)

y <- tribble(
  ~a, ~b,
   1,  1, 
   1,  2
)

Operaciones que puedo realizar:

intersect(x,y)
union(x,y)
setdiff(x,y)