データ分析では、1つの表のデータだけを扱うことは稀です。 実際には、分析に必要な多くの表があり、それらを組み合わせるための柔軟なツールが必要となります。 dplyr には、同時に2つの表を扱う3種類の動詞があります。
別の表の一致する行から1つの表に新しい変数を追加する変異結合。
フィルタリング結合:一方の表の観測値が他方の表の観測値と一致するかどうかに基づいて、観測値をフィルタリングします。
データセット内観測値を、あたかもセットの要素であるかのように組み合わせるセット操作。
(ここでは、行がオブザベーション、列が変数であるTidy dataを想定しています。このフレームワークに慣れていない方は、まずそれを読むことをお勧めします)。
すべての2表式の動詞は同様に動作します。最初の2つの引数は x
と y
で、結合する表を指定します。出力は常に x
と同じ型の新しい表になります。
変異結合は、複数の表の変数を組み合わせることができます。 例えば、nycflights13 のデータを見てみましょう。 ある表には、航空会社の略語を含むフライト情報があり、別の表には、略語とフルネームの間のマッピングがあります。 結合を使用して、フライトデータに航空会社名を追加することができます。
library("nycflights13")
# Drop unimportant variables so it's easier to understand the join results.
flights2 <- flights %>% select(year:day, hour, origin, dest, tailnum, carrier)
flights2 %>%
left_join(airlines)
#> Joining, by = "carrier"
#> # A tibble: 336,776 x 9
#> year month day hour origin dest tailnum carrier name
#> <int> <int> <int> <dbl> <chr> <chr> <chr> <chr> <chr>
#> 1 2013 1 1 5 EWR IAH N14228 UA United Air Lines Inc.
#> 2 2013 1 1 5 LGA IAH N24211 UA United Air Lines Inc.
#> 3 2013 1 1 5 JFK MIA N619AA AA American Airlines Inc.
#> 4 2013 1 1 5 JFK BQN N804JB B6 JetBlue Airways
#> 5 2013 1 1 6 LGA ATL N668DN DL Delta Air Lines Inc.
#> # … with 336,771 more rows
x
と y
と同様に、それぞれの変異結合は引数 by
を取り、2つの表のオブザベーションをマッチさせるためにどの変数を使うかをコントロールします。 これを指定するにはいくつかの方法がありますが、以下に nycflights13 の様々な表を使って説明します。
dplyr は、両方の表に現れるすべての変数を使用し、 natural 結合を行います。 例えば、flight 表と weather 表は、共通の変数である year, month, day, hour, origin で結合します。
flights2 %>% left_join(weather)
#> Joining, by = c("year", "month", "day", "hour", "origin")
#> # A tibble: 336,776 x 18
#> year month day hour origin dest tailnum carrier temp dewp humid
#> <int> <int> <int> <dbl> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
#> 1 2013 1 1 5 EWR IAH N14228 UA 39.0 28.0 64.4
#> 2 2013 1 1 5 LGA IAH N24211 UA 39.9 25.0 54.8
#> 3 2013 1 1 5 JFK MIA N619AA AA 39.0 27.0 61.6
#> 4 2013 1 1 5 JFK BQN N804JB B6 39.0 27.0 61.6
#> 5 2013 1 1 6 LGA ATL N668DN DL 39.9 25.0 54.8
#> # … with 336,771 more rows, and 7 more variables: wind_dir <dbl>,
#> # wind_speed <dbl>, wind_gust <dbl>, precip <dbl>, pressure <dbl>,
#> # visib <dbl>, time_hour <dttm>
文字ベクトル、by = "x"
。 自然結合のようなものですが、共通の変数の一部だけを使用します。 例えば、flights
と planes
は year
列を持っていますが、それらは異なる意味を持っているので、 tailnum
でのみ結合したいとします。
flights2 %>% left_join(planes, by = "tailnum")
#> # A tibble: 336,776 x 16
#> year.x month day hour origin dest tailnum carrier year.y type
#> <int> <int> <int> <dbl> <chr> <chr> <chr> <chr> <int> <chr>
#> 1 2013 1 1 5 EWR IAH N14228 UA 1999 Fixed wing multi…
#> 2 2013 1 1 5 LGA IAH N24211 UA 1998 Fixed wing multi…
#> 3 2013 1 1 5 JFK MIA N619AA AA 1990 Fixed wing multi…
#> 4 2013 1 1 5 JFK BQN N804JB B6 2012 Fixed wing multi…
#> 5 2013 1 1 6 LGA ATL N668DN DL 1991 Fixed wing multi…
#> # … with 336,771 more rows, and 6 more variables: manufacturer <chr>,
#> # model <chr>, engines <int>, seats <int>, speed <int>, engine <chr>
なお,出力される年の列は,接尾語で曖昧さが解消されています.
名前付き文字ベクトル: by = c("x" = "a")
。 これは表 x
の変数 x
と表 y
の変数 a
をマッチさせます。 使用された変数は出力に使用されます。
各フライトには出発地と目的地の airport
があるので、どちらに結合したいかを指定する必要があります。
flights2 %>% left_join(airports, c("dest" = "faa"))
#> # A tibble: 336,776 x 15
#> year month day hour origin dest tailnum carrier name lat lon alt
#> <int> <int> <int> <dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
#> 1 2013 1 1 5 EWR IAH N14228 UA George… 30.0 -95.3 97
#> 2 2013 1 1 5 LGA IAH N24211 UA George… 30.0 -95.3 97
#> 3 2013 1 1 5 JFK MIA N619AA AA Miami … 25.8 -80.3 8
#> 4 2013 1 1 5 JFK BQN N804JB B6 <NA> NA NA NA
#> 5 2013 1 1 6 LGA ATL N668DN DL Hartsf… 33.6 -84.4 1026
#> # … with 336,771 more rows, and 3 more variables: tz <dbl>, dst <chr>,
#> # tzone <chr>
flights2 %>% left_join(airports, c("origin" = "faa"))
#> # A tibble: 336,776 x 15
#> year month day hour origin dest tailnum carrier name lat lon alt
#> <int> <int> <int> <dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
#> 1 2013 1 1 5 EWR IAH N14228 UA Newark… 40.7 -74.2 18
#> 2 2013 1 1 5 LGA IAH N24211 UA La Gua… 40.8 -73.9 22
#> 3 2013 1 1 5 JFK MIA N619AA AA John F… 40.6 -73.8 13
#> 4 2013 1 1 5 JFK BQN N804JB B6 John F… 40.6 -73.8 13
#> 5 2013 1 1 6 LGA ATL N668DN DL La Gua… 40.8 -73.9 22
#> # … with 336,771 more rows, and 3 more variables: tz <dbl>, dst <chr>,
#> # tzone <chr>
変異結合には4つのタイプがあり、マッチしなかった場合の動作が異なります。簡単な例を挙げてそれぞれを説明します。
inner_join(x, y)
は、x
とy
の両方にマッチする観測値のみを含みます。
x | y | a | b |
---|---|---|---|
1 | 2 | 10 | a |
left_join(x, y)
は、x
にあるすべての観測値を、それがマッチするかどうかにかかわらず、含みます。 これは、主表からの観測値を失わないようにするため、最もよく使われる結合です。
right_join(x, y)
は y
のすべての観測値を含みます。 これは left_join(y, x)
と同等ですが、列と行の順序が異なります。
full_join()
は、x
とy
のすべての観測値を含みます。
左結合、右結合、完全結合を総称して 外側結合 と呼びます。 外側結合で行が一致しない場合、新しい変数には欠落した値が入力されます。
変異結合は主に新しい変数の追加に使用されますが、新しい観測値を生成することもできます。 一致するものが一意でない場合、結合は一致する観測値のすべての可能な組み合わせ(デカルト積)を追加します。
フィルタリング結合は変異結合と同じ方法で観測値をマッチさせますが、変数ではなく観測値に影響を与えます。 2つのタイプがあります。
semi_join(x, y)
keeps x
にあるすべての観測値で y
にマッチするもの。anti_join(x, y)
drops y
にマッチする x
内のすべての観測値を削除します。これらは結合のミスマッチを診断するために最も有用です。 例えば、nycflights13 データセットの中には、planes 表の中に一致する tail 番号を持たない多くのフライトがあります。
library("nycflights13")
flights %>%
anti_join(planes, by = "tailnum") %>%
count(tailnum, sort = TRUE)
#> # A tibble: 722 x 2
#> tailnum n
#> <chr> <int>
#> 1 <NA> 2512
#> 2 N725MQ 575
#> 3 N722MQ 513
#> 4 N723MQ 507
#> 5 N713MQ 483
#> # … with 717 more rows
もし、結合がどの観測値にマッチするか心配ならば、semi_join()
または anti_join()
から始めてください。 semi_join()
や anti_join()
は、重複することはなく、観測値を削除するだけです。
df1 <- tibble(x = c(1, 1, 3, 4), y = 1:4)
df2 <- tibble(x = c(1, 1, 2), z = c("a", "b", "a"))
# Four rows to start with:
df1 %>% nrow()
#> [1] 4
# And we get four rows after the join
df1 %>% inner_join(df2, by = "x") %>% nrow()
#> [1] 4
# But only two rows actually match
df1 %>% semi_join(df2, by = "x") %>% nrow()
#> [1] 2
2つの表の動詞の最後のタイプは集合演算です。 これらは x
と y
の入力が同じ変数を持つことを想定しており、観測値を集合のように扱います。
intersect(x, y)
: x
と y
の両方に含まれる観測値のみを返す。union(x, y)
: x
と y
に含まれるユニークな観測値を返す。setdiff(x, y)
: x
に含まれるが y
には含まれない観測値を返す。この単純なデータを考えると
(df1 <- tibble(x = 1:2, y = c(1L, 1L)))
#> # A tibble: 2 x 2
#> x y
#> <int> <int>
#> 1 1 1
#> 2 2 1
(df2 <- tibble(x = 1:2, y = 1:2))
#> # A tibble: 2 x 2
#> x y
#> <int> <int>
#> 1 1 1
#> 2 2 2
4つの可能性があります。:
intersect(df1, df2)
#> # A tibble: 1 x 2
#> x y
#> <int> <int>
#> 1 1 1
# Note that we get 3 rows, not 4
union(df1, df2)
#> # A tibble: 3 x 2
#> x y
#> <int> <int>
#> 1 1 1
#> 2 2 1
#> 3 2 2
setdiff(df1, df2)
#> # A tibble: 1 x 2
#> x y
#> <int> <int>
#> 1 2 1
setdiff(df2, df1)
#> # A tibble: 1 x 2
#> x y
#> <int> <int>
#> 1 2 2
dplyr は、3つ以上の表を扱うための関数を提供していません。その代わりに、Advanced Rで説明されているように、 purrr::reduce()
または Reduce()
を使用して、2つの表の動詞を反復的に組み合わせて、必要な数の表を処理します。