Tema 03 - Manipulación de datos relacionales

Pedro Albarrán

Dpto. de Fundamentos del Análisis Económico. Universidad de Alicante

Alberto Pérez

Múltiples tablas de datos

  • Analizar datos suele implicar múltiples tablas

    • diferentes orígenes: ej., dptos. de empresa (personal, ventas, almacén)

    • almacenamiento más eficiente: elementos “similares” dentro de una tabla y diferentes entre ellas

  • Para poder combinar la información los datos deben ser relacionales: cada par de tablas están relacionadas mediante identificadores llamados claves

  • P.e., la biblioteca nycflights13 contiene varias tablas: el nombre de la compañía está “codificado” en flights y se puede encontrar en airlines
flights %>% select(dep_time,arr_time,carrier:dest) 
airlines
  • Ambas tablas contienen un identificador común clave (“key”): carrier

Relaciones entre tablas

Datos relacionales

  • Tipos de claves:

    • Primaria (o interna): identifican de forma única cada observación en una tabla. Puede ser una sola variable (en planes) o múltiples (en weather)

      • Subrogada = número de fila, si la tabla carece de identificación única
    • Secundaria (o externa): señala a la clave primaria de otra tabla

  • Una clave primaria y una externa (asociada) en otra tabla forman una relación:

    • de uno-a-muchos (ej., vuelos y aviones), de uno-a-uno, de muchos-a-muchos (ej., aerolíneas y aeropuertos), de muchos-a-uno
  • Operaciones que se pueden realizar con dos tablas: uniones de transformación, uniones de filtro y operaciones de conjunto

Uniones de transformación

  • Añaden nuevas variables a una tabla desde filas coincidentes en otra.

  • Ejemplo:

  • cbind() o bind_columns(): nuevas columnas para filas en el mismo orden
  • Dos argumentos obligatorios: las tablas que se unen
# queremos añadir el nombre de las compañias en la tabla de vuelos
flights2 <- flights %>% 
              select(year:day, hour, origin, dest, carrier, tailnum)
airlines

Argumento by: ¿Cómo se emparejan las tablas?

  • Las claves (variables que relacionan ambas tablas) se indican, para una variable, con by = "varX" o, para varias, con by = c("varX", "varY")
flights2 %>% inner_join(airlines, by = "carrier") 
flights2 %>% inner_join(weather, 
                by = c("year", "month", "day", "hour", "origin"))
  • Si se omite el argumento by, se usan todas las variables en común. Esto no siempre es deseable: ej., año no es lo mismo en flights y planes

  • Columnas con el mismo nombre (ej., año) se desambigúan con un sufijo

flights2 %>% left_join(planes, by = c("tailnum"))
  • by = c("x1" = "y1", "x2" = "y2") para emparejar la variable x1 en la primera tabla con la variable y1 en la segunda, y la variable x2 con y2
flights2 %>% left_join(airports, 
                  by = c("dest" = "faa"))    # aeropuerto de destino

Unión interna

df1 <- tibble(clave = c(1:3), val_x = c("x1", "x2", "x3"))
df2 <- tibble(clave = c(1:2, 4), val_y = c("y1","y2","y4"))
  • inner_join(x, y) sólo incluye observaciones que coincidan en x y y.
df1 %>% inner_join(df2, by = "clave")

Uniones externas

  • Cuando una fila no coincide en una unión externa, las nuevas variables se rellenan como valores ausentes

  • left_join(df1, df2): mantiene todas las observaciones en x, coincidan o no con la de y

    • (no se pierden observaciones de la tabla primaria)
  • right_join(df1, df2): mantiene todas las observaciones en y

  • full_join(df1, df2): incluye todas las observaciones de x e y

Claves duplicadas

  • Si una coincidencia no es única, se generan todas las combinaciones posibles (producto cartesiano) de las observaciones coincidentes
  • En una tabla: añade información en una relación de uno a muchos.
  • En ambas tablas: igualmente, todas las combinaciones posibles
    • posible error: NO hay clave primaria única

Uniones de filtro

  • Filtra las observaciones de la tabla de la izquierda basándose en si coinciden o no con una observación de la otra tabla

  • Se tiene un subconjunto de las filas de la tabla de la izquierda

  • semi_join(x, y) mantiene las observaciones en x que están en y

df1 %>% semi_join(df2, 
          by = "clave")
  • anti_join(x, y) elimina las observaciones en x que están en y

df1 %>% anti_join(df2, 
          by = "clave")

Uniones de filtro (cont.)

  • Claves duplicadas: en uniones de filtro sólo importa la existencia de una coincidencia, NO qué observación coincida \(\Rightarrow\) NUNCA duplica filas
  • Las uniones de filtro son útiles para diagnosticar desajustes de uniones (qué observaciones serán emparejadas)
flights %>% anti_join(planes, by = "tailnum") %>%   # vuelos sin información del avión
              count(tailnum, sort = TRUE)
  • Pueden ser equivalentes a usar filter(), con tablas previamente resumidas, pero permiten filtrados complejos fácilmente

Operaciones de conjunto

  • Trabajan con filas completas, comparando valores de cada variable.

  • Esperan que x e y tengan las mismas variables, y tratan las observaciones (filas) como elementos de un conjunto.

  • Útil cuando se quiere dividir un filtro complejo en piezas más simples.

df1 <- tibble(x = 1:2, y = c(1, 1))
df2 <- tibble(x = c(1,1), y = 1:2)

intersect(df1, df2)     # solo filas tanto en df1 como en df2
union(df1, df2)         # filas únicas en ambas tablas df1 y df2` 
union_all(df1, df2)     # todas las filas de df1 y df2, manteniendo duplicados 
setdiff(df1, df2)       # filas en df1, pero no en df2
setdiff(df2, df1)