Two-table verbs
2015-06-15
Перевод
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
.
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, для итеративного объединения двухтабличным глаголов с целью обработки нужного количества таблиц.
Комментариев нет:
Отправить комментарий