-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path2table_verbs.Rmd
264 lines (180 loc) · 10.3 KB
/
2table_verbs.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
---
title: "Two-table verbs"
output: html_document
date: '2015-06-15'
---
### Перевод
### https://cran.r-project.org/web/packages/dplyr/vignettes/two-table.html
```{r, echo=FALSE, warning=FALSE, message=FALSE}
setwd("D:/GITHUB/dplyr_doc_ru")
library(dplyr)
```
Анализ данных редко включает всего одну таблицу с данными. На практике, как правило, вы будете иметь много таблиц, которые вносят вклад в анализ, и вам потребуются гибкие инструменты, чтобы объединять их. В dplyr есть три семейства глаголов, которые работают с двумя таблицами одновременно:
* Трансформирующие объединения, которые добавляют новые переменные в одну таблицу из соответствующих строк другой.
* Фильтрующие объединения, которые отфильтровывают наблюдения из одной таблицы на основании соответствия или несоответствия наблюдениям из другой таблицы.
* Операции для наборов, которые объединяют наблюдения в наборах данных как если бы они были элементами [одного] набора.
(Это обсуждение подразумевает, что у вас есть [чистые данные](http://www.jstatsoft.org/v59/i10/), где строки являются наблюдениями, а колонки - переменными. Если вы не знакомы с этим фреймворком, я рекомендую сперва ознакомиться.)
Все двухтабличные глаголы работают подобным образом. Первые два аргумента - это `x` и `y`, которые представляют объединяемые таблицы. Результат всегда является новой таблицей того же типа, что и `x`.
## Трансформирующие объединения
Трансформирующие объединения позволяют вам комбинировать переменные из нескольких таблиц. Например, возьмем набор данных nycflights13. В одной таблице у нас информация о рейсах с аббревиатурой для авиаперевозчика, а в другой - соответствия между аббревиатурами и полными названиями. Вы можете использовать объединение для добавления названий авиаперевозчиков к данных о рейсах:
```{r}
library("nycflights13")
# Убираем неважные переменные для лучшего понимания результата.
flights2 <- flights %>% select(year:day, hour, origin, dest, tailnum, carrier)
flights2 %>%
left_join(airlines)
```
### Управление соответствием таблиц
Наряду с `x` и `y` каждое трансформирующее объединение принимает аргумент `by`, который контроллирует, какие переменные используются для установки соответствия наблюдений в двух таблицах. Есть несколько способов его задать, как я покажу ниже с различными таблицами из набора данных nycflights13:
* `NULL`, по умолчанию. dplyr будет использовать все переменные, которые присутствуют в обеих таблицах, объединяя естественным способом. Например, таблицы flights и weather соответствуют друг другу по их общим переменным: year, month, day, hour и origin.
```{r}
flights2 %>% left_join(weather)
```
Обратите внимание, что у колонок year конфликт имён устраняется с помощью суффиксов.
* Символьный вектор с именами: `by = c("x" = "a")`. Такие выражение сопоставит переменную `x` таблицы `x` и переменную `a` таблицы `b` (*видимо, подразумевалась таблица `y` - прим. пер.*).
Каждый полет имеет исходный аэропорт и аэропорт назначения, так что мы должны указать, по какому их них мы хотим произвести объединение:
```{r}
flights2 %>% left_join(airports, c("dest" = "faa"))
```
```{r}
flights2 %>% left_join(airports, c("origin" = "faa"))
```
### Типы объединений
Есть четыре типа трансформирующих объединений, которые различаются своим поведением, если соответствие не найдено. Мы покажем каждый из них на простом примере:
```{r}
(df1 <- data_frame(x = c(1, 2), y = 2:1))
```
```{r}
(df2 <- data_frame(x = c(1, 3), a = 10, b = "a"))
```
* `inner_join(x, y)` включает только наблюдения, которые есть и в `x`, и в `y`.
```{r}
df1 %>% inner_join(df2) %>% knitr::kable()
```
* `left_join(x, y)` включает все наблюдениях из `x` независимо от того, имеют они соответствие или нет. Это наиболее часто используемый тип объединения, поскольку он гарантирует, что вы не потеряете наблюдения из вашей основной таблицы.
```{r}
df1 %>% left_join(df2)
```
* `right_join(x, y)` включает все наблюдения `y`. Эквивалентно `left_join(y, x)`, но с другим порядком столбцов.
```{r}
df1 %>% right_join(df2)
```
```{r}
df2 %>% left_join(df1)
```
* `full_join()` включает все наблюдения из `x` и `y`.
```{r}
df1 %>% full_join(df2)
```
Левое, правое и полное объединения вместе известны как **внешние объединения**. Когда строка не имеет соответствия во внешнем объединении, новые переменные заполняются пропущенными значениями.
### Наблюдения
В то время как трансформирующие объединения в основном используются для добавления новых переменных, они также могут добавлять новые наблюдения. Если соответствие не уникально, объединение будет добавлять все возможные комбинации (декартово произведение) соответствующих наблюдений:
```{r}
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)
```
## Фильтрующие объединения
Фильтрующие объединения устанавливают соответствие наблюдений таким же образом, как и трансформирующие объединения, но затрагивают наблюдения, а не переменные. Есть два типа:
* `semi_join(x, y)` **сохраняют** все наблюдения в `x`, которые имеют соответствие в `y`.
* `anti_join(x, y)` **удаляют** все наблюдения в `x`, которые имеют соответствие в `y`.
Они наиболее полезны для диагностики несоответствий при объединении. Например, в наборе данных nycflights13 есть много рейсов, которые не имеют соответствующего хвостового номера в таблице planes:
```{r}
library("nycflights13")
flights %>%
anti_join(planes, by = "tailnum") %>%
count(tailnum, sort = TRUE)
```
Если вы беспокоитесь о том, какие наблюдения из объединяемых вами будут иметь соответствия, начните с `semi_join()` или `anti_join()`. `semi_join()` и `anti_join()` никогда не дублируют; они только удаляют наблюдения.
```{r}
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()
# И имеем 4 строки после объединения
df1 %>% inner_join(df2, by = "x") %>% nrow()
# Но только 2 строки на самом деле соответствуют
df1 %>% semi_join(df2, by = "x") %>% nrow()
```
## Операции для наборов
Последний тип двухтабличных глаголов - операции для наборов. Они подразумевают, что `x` и `y` имеют одинаковые переменные, рассматривают наблюдения как наборы:
* `intersect(x, y)`: возвращает только наблюдения, которые есть и в `x`, и в `y`
* `union(x, y)`: возвращает уникальные наблюдения в `x` и `y`
* `setdiff(x, y)`: возвращает наблюдения, которые есть в `x`, но не в `y`.
Возьмём эти простые данные:
```{r}
(df1 <- data_frame(x = 1:2, y = c(1L, 1L)))
```
```{r}
(df2 <- data_frame(x = 1:2, y = 1:2))
```
Есть четыре варианта:
```{r}
intersect(df1, df2)
```
```{r}
# Обратите внимание, мы получили 3 строки, а не 4
union(df1, df2)
```
```{r}
setdiff(df1, df2)
```
```{r}
setdiff(df2, df1)
```
## Базы данных
Каждый двухтабличный глагол имеет простой 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) с предупреждением:
```{r}
df1 <- data_frame(x = 1, y = factor("a"))
df2 <- data_frame(x = 2, y = factor("b"))
full_join(df1, df2) %>% str()
```
* Факторы с одинаковыми уровнями в разном порядке приводятся к символьному типу с предупреждением:
```{r}
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()
```
* Факторы сохраняются, только если их уровни в точности совпадают:
```{r}
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()
```
* Фактор и переменная типа character приводятся к символьному типу с предупреждением:
```{r}
df1 <- data_frame(x = 1, y = "a")
df2 <- data_frame(x = 2, y = factor("a"))
full_join(df1, df2) %>% str()
```
В противном случае логические значения без предупреждений превращаются в целые числа, целые числа - в числа, но приведение к символьному типу вызовет ошибку:
```{r}
df1 <- data_frame(x = 1, y = 1L)
df2 <- data_frame(x = 2, y = 1.5)
full_join(df1, df2) %>% str()
```
```{r, eval=FALSE}
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](http://adv-r.had.co.nz/Functionals.html#functionals-fp), для итеративного объединения двухтабличным глаголов с целью обработки нужного количества таблиц.