2 つの表、1 つのキー
実際のデータが 1 つの表に収まっていることはめったにありません。顧客はあるデータフレームに、その注文は別のデータフレームにあり、「各顧客はいくら使ったか?」という問いには両方が必要です。両者をつなぐのが キー です。同じ実体を識別する、それぞれの表にある列のことです。キーで表を組み合わせることを ジョイン(SQL の言葉)または マージ(base R の言葉)と呼びます。同じ操作です。
このページの残りで使う 2 つの表がこちらです。顧客 5 は注文しているのに顧客の表にはおらず、顧客 2 と 4 は一度も注文していない点に注目してください。
この不一致は意図的なものです。一致しない行をジョインがどう扱うかこそ、ジョインの種類を分けるものだからです。
merge(): 既定は内部結合
merge(x, y, by = "key") はキーが等しい行を対応付け、その列どうしを貼り合わせます。既定では 両方の表に存在するキーだけ を残します — 内部結合です。
3 行が返ります。Ana は 2 回 現れます — 彼女には注文が 2 件あり、ジョインは一致する 組 ごとに 1 つの出力行を生むからです。Ben と Dana は消え(注文なし)、顧客 5 の謎の注文も消えます(顧客なし)。内部結合は両方の表から一致しない行を黙って捨てます — 完全な組だけを気にするときはまさに正しい動作ですが、そうでないときは静かなデータ欠落のバグになります。
左結合・右結合・完全結合: all.x, all.y, all
一致しない行を残すには、どちらの表の行が神聖なのかを指定します。all.x = TRUE は最初の表のすべての行を残します — 左結合 で、実務で最もよく使われるジョインです。
これで Ben と Dana が amount を NA にして生き残ります — 「この顧客は存在するが、一致する注文がない」という意味です。この NA はゴミではなく情報です。is.na(result$amount) はまさに一度も注文しなかった顧客のリストです(その扱い方は 欠損値のドキュメント が扱っています)。残りの変種は同じ考えを別の方向に向けたものです。all.y = TRUE は 2 番目の表のすべての行を残し(右結合 — 未知の顧客 5 からの注文が name を NA にして残ります)、all = TRUE は両側のすべてを残します(完全結合)。
こう問いかけて選びましょう。失ってはいけないのはどちらの行か? マスター表を参照データで補強するなら左結合で、マスター表を先に置きます。両方向を監査するなら完全結合です。
異なるキー名: by.x と by.y
表どうしで命名が一致していることはめったにありません — 一方は id、他方は customer_id。名前を変更するのではなく、merge() に両方の名前を伝えましょう。
出力ではキーに最初の表の名前が残ります。関連して、2 つの表が キー以外の 列名を共有している場合(たとえば両方に date がある場合)、merge はそれらに date.x と date.y という接尾辞を付けます — 読みにくいので、すみやかに名前を変更しましょう。
dplyr のジョイン
dplyr は各ジョインの種類にそれぞれの動詞を与えるので、意図がフラグ引数ではなく関数名に表れます(静的な例です。サンドボックスは base R しか実行しません)。
library(dplyr)
left_join(customers, orders, by = "id")
inner_join(customers, orders, by = "id")
full_join(customers, orders, by = "id")
left_join(customers, orders, by = c("id" = "customer_id")) # different names
読みやすさに加えて、left_join() は最初の表の行順を保持し(merge() はキーで並べ替えます)、多対多の一致について大きな声で警告します — 動詞ファミリーについては dplyr 入門 を参照してください。
過小評価されているメンバーが anti_join() です。2 番目の表に 一致がない 最初の表の行を返します — 列は追加されず、残り物だけが返ります。
anti_join(customers, orders, by = "id") # customers who never ordered
「どの行が一致しなかったか?」という問いは、データ整備で絶えず出てきます(一致しない ID、孤立したレコード、失敗した照合)。base R では customers[!(customers$id %in% orders$id), ] が必要なところを、anti_join() は 1 回の呼び出しで答えます。
行を積み重ねる: rbind()
ジョインは 2 つの表の 列 を組み合わせます。代わりに 同じ種類 の行の束が 2 つある場合 — 1 月の注文と 2 月の注文 — は rbind() で積み重ねます。
要件は厳格です。両方のデータフレームが同じ列名を持たなければなりません(順序は自由です — rbind は名前で対応付けます)。列の不足や余分はエラーであり、NA で埋められることはありません。束ごとに列がずれている場合は、dplyr の bind_rows() の方が寛容です — 名前で揃え、欠けた部分を NA で埋めます。
キー重複による爆発
古典的なジョインの事故は、一意だと信じていたキーが実は一意でない — しかも 両方の 表で — というものです。すべての一致がすべての一致と組み合わさり、行が掛け算されます。
2 行と 2 行のジョインが 4 行を生みます — 各 x が各 y と組み合わさるからです。実データでは、これが 1 万行の表を 300 万行に、売上合計を 2 倍にする仕組みです。merge() はこれを黙って行います。防御策は習慣です。ジョインの前に、一意だと仮定しているキーを確認し(anyDuplicated(customers$id) が 0 であるべきです)、ジョインの後に nrow() を期待値と照合しましょう。
この記事のまとめ
merge(x, y, by = "key")は内部結合です — 一致しない行は黙って消えます。all.x = TRUE(左)、all.y = TRUE(右)、all = TRUE(完全)は一致しない行を残し、NAで埋めます。- キー名が異なる場合、base では
by.x/by.y、dplyr ではby = c("a" = "b")を使います。 - dplyr は各ジョインに名前を与えます。過小評価されているのは、一致 しなかった 行を返す
anti_join()です。 rbind()は同じ形の表を積み重ねます。列は名前で一致しなければなりません。- キーの重複は黙って行を掛け算します — 前に
anyDuplicated()、後にnrow()を確認しましょう。
次は 横持ちと縦持ちの間の変形 — pivot_longer() と pivot_wider() です。
よくある質問
R で 2 つのデータフレームを結合するにはどうすればよいですか?
共通のキー列を指定して merge(x, y, by = "key") を使います。既定では内部結合を行い、キーが両方のデータフレームに現れる行だけが残ります。左結合には all.x = TRUE、右結合には all.y = TRUE、完全結合には all = TRUE を加えます。
R で左結合を行うにはどうすればよいですか?
base R では merge(x, y, by = "key", all.x = TRUE) が x のすべての行を残し、一致がない箇所の y の列を NA で埋めます。dplyr では left_join(x, y, by = "key") — 結果は同じで、さらに merge() がしない x の元の行順も保持します。
キー列の名前が異なる場合、どうやってデータフレームを結合しますか?
merge() に両方の名前を伝えます: merge(x, y, by.x = "id", by.y = "customer_id")。dplyr での等価物は left_join(x, y, by = c("id" = "customer_id"))、あるいは現代的なヘルパーを使って by = join_by(id == customer_id) です。
R の merge と rbind の違いは何ですか?
結合する方向が違います。merge() は 2 つの表の行をキーで対応付け、それらの列を組み合わせます — ジョインです。rbind() は一方の表の行をもう一方の下に積み重ねます — 両者は同じ列名を持つ必要があります。列が同一の月次ファイルには rbind() を、顧客と注文の組み合わせには merge() を使いましょう。