воскресенье, 16 августа 2015 г.

dplyr. Two-table verbs (перевод)


Перевод

https://cran.r-project.org/web/packages/dplyr/vignettes/two-table.html



Анализ данных редко включает всего одну таблицу с данными. На практике, как правило, вы будете иметь много таблиц, которые вносят вклад в анализ, и вам потребуются гибкие инструменты, чтобы объединять их. В dplyr есть три семейства глаголов, которые работают с двумя таблицами одновременно:
  • Трансформирующие объединения, которые добавляют новые переменные в одну таблицу из соответствующих строк другой.
  • Фильтрующие объединения, которые отфильтровывают наблюдения из одной таблицы на основании соответствия или несоответствия наблюдениям из другой таблицы.
  • Операции для наборов, которые объединяют наблюдения в наборах данных как если бы они были элементами [одного] набора.
(Это обсуждение подразумевает, что у вас есть чистые данные, где строки являются наблюдениями, а колонки - переменными. Если вы не знакомы с этим фреймворком, я рекомендую сперва ознакомиться.)
Все двухтабличные глаголы работают подобным образом. Первые два аргумента - это x и y, которые представляют объединяемые таблицы. Результат всегда является новой таблицей того же типа, что и x.

Трансформирующие объединения

Трансформирующие объединения позволяют вам комбинировать переменные из нескольких таблиц. Например, возьмем набор данных nycflights13. В одной таблице у нас информация о рейсах с аббревиатурой для авиаперевозчика, а в другой - соответствия между аббревиатурами и полными названиями. Вы можете использовать объединение для добавления названий авиаперевозчиков к данных о рейсах:
library("nycflights13")
# Убираем неважные переменные для лучшего понимания результата.
flights2 <- flights %>% select(year:day, hour, origin, dest, tailnum, carrier)

flights2 %>% 
  left_join(airlines)
## Joining by: "carrier"
## Warning in left_join_impl(x, y, by$x, by$y): joining factor and character
## vector, coercing into character vector
## Source: local data frame [336,776 x 9]
## 
##    year month day hour origin dest tailnum carrier
## 1  2013     1   1    5    EWR  IAH  N14228      UA
## 2  2013     1   1    5    LGA  IAH  N24211      UA
## 3  2013     1   1    5    JFK  MIA  N619AA      AA
## 4  2013     1   1    5    JFK  BQN  N804JB      B6
## 5  2013     1   1    5    LGA  ATL  N668DN      DL
## 6  2013     1   1    5    EWR  ORD  N39463      UA
## 7  2013     1   1    5    EWR  FLL  N516JB      B6
## 8  2013     1   1    5    LGA  IAD  N829AS      EV
## 9  2013     1   1    5    JFK  MCO  N593JB      B6
## 10 2013     1   1    5    LGA  ORD  N3ALAA      AA
## ..  ...   ... ...  ...    ...  ...     ...     ...
## Variables not shown: name (fctr)

Управление соответствием таблиц

Наряду с x и y каждое трансформирующее объединение принимает аргумент by, который контроллирует, какие переменные используются для установки соответствия наблюдений в двух таблицах. Есть несколько способов его задать, как я покажу ниже с различными таблицами из набора данных nycflights13:
  • NULL, по умолчанию. dplyr будет использовать все переменные, которые присутствуют в обеих таблицах, объединяя естественным способом. Например, таблицы flights и weather соответствуют друг другу по их общим переменным: year, month, day, hour и origin.
flights2 %>% left_join(weather)
## Joining by: c("year", "month", "day", "hour", "origin")
## Source: local data frame [336,776 x 17]
## 
##    year month day hour origin dest tailnum carrier temp dewp humid
## 1  2013     1   1    5    EWR  IAH  N14228      UA   NA   NA    NA
## 2  2013     1   1    5    LGA  IAH  N24211      UA   NA   NA    NA
## 3  2013     1   1    5    JFK  MIA  N619AA      AA   NA   NA    NA
## 4  2013     1   1    5    JFK  BQN  N804JB      B6   NA   NA    NA
## 5  2013     1   1    5    LGA  ATL  N668DN      DL   NA   NA    NA
## 6  2013     1   1    5    EWR  ORD  N39463      UA   NA   NA    NA
## 7  2013     1   1    5    EWR  FLL  N516JB      B6   NA   NA    NA
## 8  2013     1   1    5    LGA  IAD  N829AS      EV   NA   NA    NA
## 9  2013     1   1    5    JFK  MCO  N593JB      B6   NA   NA    NA
## 10 2013     1   1    5    LGA  ORD  N3ALAA      AA   NA   NA    NA
## ..  ...   ... ...  ...    ...  ...     ...     ...  ...  ...   ...
## Variables not shown: wind_dir (dbl), wind_speed (dbl), wind_gust (dbl),
##   precip (dbl), pressure (dbl), visib (dbl)
Обратите внимание, что у колонок year конфликт имён устраняется с помощью суффиксов.
  • Символьный вектор с именами: by = c("x" = "a"). Такие выражение сопоставит переменную x таблицы x и переменную a таблицы b (видимо, подразумевалась таблица y - прим. пер.).
Каждый полет имеет исходный аэропорт и аэропорт назначения, так что мы должны указать, по какому их них мы хотим произвести объединение:
flights2 %>% left_join(airports, c("dest" = "faa"))
## Source: local data frame [336,776 x 14]
## 
##    year month day hour origin dest tailnum carrier
## 1  2013     1   1    5    EWR  IAH  N14228      UA
## 2  2013     1   1    5    LGA  IAH  N24211      UA
## 3  2013     1   1    5    JFK  MIA  N619AA      AA
## 4  2013     1   1    5    JFK  BQN  N804JB      B6
## 5  2013     1   1    5    LGA  ATL  N668DN      DL
## 6  2013     1   1    5    EWR  ORD  N39463      UA
## 7  2013     1   1    5    EWR  FLL  N516JB      B6
## 8  2013     1   1    5    LGA  IAD  N829AS      EV
## 9  2013     1   1    5    JFK  MCO  N593JB      B6
## 10 2013     1   1    5    LGA  ORD  N3ALAA      AA
## ..  ...   ... ...  ...    ...  ...     ...     ...
## Variables not shown: name (chr), lat (dbl), lon (dbl), alt (int), tz
##   (dbl), dst (chr)
flights2 %>% left_join(airports, c("origin" = "faa"))
## Source: local data frame [336,776 x 14]
## 
##    year month day hour origin dest tailnum carrier                name
## 1  2013     1   1    5    EWR  IAH  N14228      UA Newark Liberty Intl
## 2  2013     1   1    5    LGA  IAH  N24211      UA          La Guardia
## 3  2013     1   1    5    JFK  MIA  N619AA      AA John F Kennedy Intl
## 4  2013     1   1    5    JFK  BQN  N804JB      B6 John F Kennedy Intl
## 5  2013     1   1    5    LGA  ATL  N668DN      DL          La Guardia
## 6  2013     1   1    5    EWR  ORD  N39463      UA Newark Liberty Intl
## 7  2013     1   1    5    EWR  FLL  N516JB      B6 Newark Liberty Intl
## 8  2013     1   1    5    LGA  IAD  N829AS      EV          La Guardia
## 9  2013     1   1    5    JFK  MCO  N593JB      B6 John F Kennedy Intl
## 10 2013     1   1    5    LGA  ORD  N3ALAA      AA          La Guardia
## ..  ...   ... ...  ...    ...  ...     ...     ...                 ...
## Variables not shown: lat (dbl), lon (dbl), alt (int), tz (dbl), dst (chr)

Типы объединений

Есть четыре типа трансформирующих объединений, которые различаются своим поведением, если соответствие не найдено. Мы покажем каждый из них на простом примере:
(df1 <- data_frame(x = c(1, 2), y = 2:1))
## Source: local data frame [2 x 2]
## 
##   x y
## 1 1 2
## 2 2 1
(df2 <- data_frame(x = c(1, 3), a = 10, b = "a"))
## Source: local data frame [2 x 3]
## 
##   x  a b
## 1 1 10 a
## 2 3 10 a
  • inner_join(x, y) включает только наблюдения, которые есть и в x, и в y.
df1 %>% inner_join(df2) %>% knitr::kable()
## Joining by: "x"
x y a b
1 2 10 a
  • left_join(x, y) включает все наблюдениях из x независимо от того, имеют они соответствие или нет. Это наиболее часто используемый тип объединения, поскольку он гарантирует, что вы не потеряете наблюдения из вашей основной таблицы.
df1 %>% left_join(df2)
## Joining by: "x"
## Source: local data frame [2 x 4]
## 
##   x y  a  b
## 1 1 2 10  a
## 2 2 1 NA NA
  • right_join(x, y) включает все наблюдения y. Эквивалентно left_join(y, x), но с другим порядком столбцов.
df1 %>% right_join(df2)
## Joining by: "x"
## Source: local data frame [2 x 4]
## 
##   x  y  a b
## 1 1  2 10 a
## 2 3 NA 10 a
df2 %>% left_join(df1)
## Joining by: "x"
## Source: local data frame [2 x 4]
## 
##   x  a b  y
## 1 1 10 a  2
## 2 3 10 a NA
  • full_join() включает все наблюдения из x и y.
df1 %>% full_join(df2)
## Joining by: "x"
## Source: local data frame [3 x 4]
## 
##   x  y  a  b
## 1 1  2 10  a
## 2 2  1 NA NA
## 3 3 NA 10  a
Левое, правое и полное объединения вместе известны как внешние объединения. Когда строка не имеет соответствия во внешнем объединении, новые переменные заполняются пропущенными значениями.

Наблюдения

В то время как трансформирующие объединения в основном используются для добавления новых переменных, они также могут добавлять новые наблюдения. Если соответствие не уникально, объединение будет добавлять все возможные комбинации (декартово произведение) соответствующих наблюдений:
df1 <- data_frame(x = c(1, 1, 2), y = 1:3)
df2 <- data_frame(x = c(1, 1, 2), z = c("a", "b", "a"))

df1 %>% left_join(df2)
## Joining by: "x"
## Source: local data frame [5 x 3]
## 
##   x y z
## 1 1 1 a
## 2 1 1 b
## 3 1 2 a
## 4 1 2 b
## 5 2 3 a

Фильтрующие объединения

Фильтрующие объединения устанавливают соответствие наблюдений таким же образом, как и трансформирующие объединения, но затрагивают наблюдения, а не переменные. Есть два типа:
  • semi_join(x, y) сохраняют все наблюдения в x, которые имеют соответствие в y.
  • anti_join(x, y) удаляют все наблюдения в x, которые имеют соответствие в y.
Они наиболее полезны для диагностики несоответствий при объединении. Например, в наборе данных nycflights13 есть много рейсов, которые не имеют соответствующего хвостового номера в таблице planes:
library("nycflights13")
flights %>% 
  anti_join(planes, by = "tailnum") %>% 
  count(tailnum, sort = TRUE)
## Source: local data frame [722 x 2]
## 
##    tailnum    n
## 1          2512
## 2   N725MQ  575
## 3   N722MQ  513
## 4   N723MQ  507
## 5   N713MQ  483
## 6   N735MQ  396
## 7   N0EGMQ  371
## 8   N534MQ  364
## 9   N542MQ  363
## 10  N531MQ  349
## ..     ...  ...
Если вы беспокоитесь о том, какие наблюдения из объединяемых вами будут иметь соответствия, начните с semi_join() или anti_join(). semi_join() и anti_join() никогда не дублируют; они только удаляют наблюдения.
df1 <- data_frame(x = c(1, 1, 3, 4), y = 1:4)
df2 <- data_frame(x = c(1, 1, 2), z = c("a", "b", "a"))

# Начинаем с 4 строк:
df1 %>% nrow()
## [1] 4
# И имеем 4 строки после объединения
df1 %>% inner_join(df2, by = "x") %>% nrow()
## [1] 4
# Но только 2 строки на самом деле соответствуют
df1 %>% semi_join(df2, by = "x") %>% nrow()
## [1] 2

Операции для наборов

Последний тип двухтабличных глаголов - операции для наборов. Они подразумевают, что x и y имеют одинаковые переменные, рассматривают наблюдения как наборы:
  • intersect(x, y): возвращает только наблюдения, которые есть и в x, и в y
  • union(x, y): возвращает уникальные наблюдения в x и y
  • setdiff(x, y): возвращает наблюдения, которые есть в x, но не в y.
Возьмём эти простые данные:
(df1 <- data_frame(x = 1:2, y = c(1L, 1L)))
## Source: local data frame [2 x 2]
## 
##   x y
## 1 1 1
## 2 2 1
(df2 <- data_frame(x = 1:2, y = 1:2))
## Source: local data frame [2 x 2]
## 
##   x y
## 1 1 1
## 2 2 2
Есть четыре варианта:
intersect(df1, df2)
## Source: local data frame [1 x 2]
## 
##   x y
## 1 1 1
# Обратите внимание, мы получили 3 строки, а не 4
union(df1, df2)
## Source: local data frame [3 x 2]
## 
##   x y
## 1 1 1
## 2 2 1
## 3 2 2
setdiff(df1, df2)
## Source: local data frame [1 x 2]
## 
##   x y
## 1 2 1
setdiff(df2, df1)
## Source: local data frame [1 x 2]
## 
##   x y
## 1 2 2

Базы данных

Каждый двухтабличный глагол имеет простой SQL-эквивалент:
R SQL
inner_join() SELECT * FROM x JOIN y ON x.a = y.a
left_join() SELECT * FROM x LEFT JOIN y ON x.a = y.a
right_join() SELECT * FROM x RIGHT JOIN y ON x.a = y.a
full_join() SELECT * FROM x FULL JOIN y ON x.a = y.a
semi_join() SELECT * FROM x WHERE EXISTS (SELECT 1 FROM y WHERE x.a = y.a)
anti_join() SELECT * FROM x WHERE NOT EXISTS (SELECT 1 FROM y WHERE x.a = y.a)
intersect(x, y) SELECT * FROM x INTERSECT SELECT * FROM y
union(x, y) SELECT * FROM x UNION SELECT * FROM y
setdiff(x, y) SELECT * FROM x EXCEPT SELECT * FROM y
x и y не обязаны быть таблицами одной базы данных. Если вы укажите copy = TRUE, dplyr скопируют таблицу y в расположение x. Это полезно, если вы загрузили набор данных с обобщёнными данными и определили представляющий интерес поднабор полных данных. Вы можете использовать semi_join(x, y, copy = TRUE) для загрузки представляющих интерес индексов во временную таблицу в той же базе данных, где находится x, а затем выполнить эффективное частичное объединение в базе данных.
Если вы работаете с большими данными, может также быть полезным установить auto_index = TRUE. Это автоматически добавит индекс к объединяемым переменным во временной таблице.

Правила приведения

При объединении таблиц dplyr является немного более консервативны, чем R сам по себе, относительно типов переменных, которые считаются эквивалентными. В основном это, вероятно, удивит, если вы работаете с факторами:
  • Факторы с разными уровнями приводятся к символьному типу (character) с предупреждением:
df1 <- data_frame(x = 1, y = factor("a"))
df2 <- data_frame(x = 2, y = factor("b"))
full_join(df1, df2) %>% str()
## Joining by: c("x", "y")
## Warning in outer_join_impl(x, y, by$x, by$y): joining factors with
## different levels, coercing to character vector
## Classes 'tbl_df', 'tbl' and 'data.frame':    2 obs. of  2 variables:
##  $ x: num  1 2
##  $ y: chr  "a" "b"
  • Факторы с одинаковыми уровнями в разном порядке приводятся к символьному типу с предупреждением:
df1 <- data_frame(x = 1, y = factor("a", levels = c("a", "b")))
df2 <- data_frame(x = 2, y = factor("b", levels = c("b", "a")))
full_join(df1, df2) %>% str()
## Joining by: c("x", "y")
## Warning in outer_join_impl(x, y, by$x, by$y): joining factors with
## different levels, coercing to character vector
## Classes 'tbl_df', 'tbl' and 'data.frame':    2 obs. of  2 variables:
##  $ x: num  1 2
##  $ y: chr  "a" "b"
  • Факторы сохраняются, только если их уровни в точности совпадают:
df1 <- data_frame(x = 1, y = factor("a", levels = c("a", "b")))
df2 <- data_frame(x = 2, y = factor("b", levels = c("a", "b")))
full_join(df1, df2) %>% str()
## Joining by: c("x", "y")
## Classes 'tbl_df', 'tbl' and 'data.frame':    2 obs. of  2 variables:
##  $ x: num  1 2
##  $ y: Factor w/ 2 levels "a","b": 1 2
  • Фактор и переменная типа character приводятся к символьному типу с предупреждением:
df1 <- data_frame(x = 1, y = "a")
df2 <- data_frame(x = 2, y = factor("a"))
full_join(df1, df2) %>% str()
## Joining by: c("x", "y")
## Warning in outer_join_impl(x, y, by$x, by$y): joining factor and character
## vector, coercing into character vector
## Classes 'tbl_df', 'tbl' and 'data.frame':    2 obs. of  2 variables:
##  $ x: num  1 2
##  $ y: chr  "a" "a"
В противном случае логические значения без предупреждений превращаются в целые числа, целые числа - в числа, но приведение к символьному типу вызовет ошибку:
df1 <- data_frame(x = 1, y = 1L)
df2 <- data_frame(x = 2, y = 1.5)
full_join(df1, df2) %>% str()
## Joining by: c("x", "y")
## Classes 'tbl_df', 'tbl' and 'data.frame':    2 obs. of  2 variables:
##  $ x: num  1 2
##  $ y: num  1 1.5
df1 <- data_frame(x = 1, y = 1L)
df2 <- data_frame(x = 2, y = "a")
full_join(df1, df2) %>% str()
#> Joining by: c("x", "y")
#> Error in eval(expr, envir, enclos): cannot join on columns 'y' x 'y': Can't join on 'y' x 'y' because of incompatible types (character / integer)

Многотабличные глаголы

dplyr не предоставляет функций для работы с тремя и более таблицами. Вместо этого используйте Reduce(), как описано в Advanced R, для итеративного объединения двухтабличным глаголов с целью обработки нужного количества таблиц.

Комментариев нет:

Отправить комментарий