Python | データ処理:pandas merge

Python
スポンサーリンク

概要(pandas.mergeは「共通キーで行を突き合わせる」SQLライクな結合)

pandas.mergeは、2つのDataFrameを共通するキー(列やインデックス)を基準に結合します。SQLのJOINと同じ発想で、片方の表にあるidやdateなどのキーを使い、対応する行を1行にまとめます。初心者がまず覚えるべきは、on(どの列で結合するか)、how(結合の種類:inner/left/right/outer)、left_on/right_on(キー名が違うとき)、suffixes(重複列名の解決)の4つです。


基本の使い方(onとhowを押さえる)

最小例(idをキーに、内部結合で突き合わせる)

import pandas as pd

users = pd.DataFrame({"id": [1, 2], "name": ["Taro", "Hanako"]})
orders = pd.DataFrame({"id": [1, 1, 3], "item": ["Book", "Pen", "Bag"]})

out = pd.merge(users, orders, on="id", how="inner")
print(out)
#    id    name  item
# 0   1    Taro  Book
# 1   1    Taro   Pen
Python

共通キーidが一致する行だけを残すのがinner(内部結合)。id=3はusers側にないため落ちます。

左結合で「主データ」を保つ(欠損はNaN)

out = pd.merge(users, orders, on="id", how="left")
print(out)
#    id    name  item
# 0   1    Taro  Book
# 1   1    Taro   Pen
# 2   2  Hanako  NaN
Python

left(左外部結合)は左側(users)の全行を残し、右側(orders)で一致がない部分はNaNになります。主データを必ず残したい時の基本形です。


結合の種類を深掘り(inner/left/right/outerの選び方)

結合タイプの違いと使いどころ

A = pd.DataFrame({"id": [1, 2], "name": ["Taro", "Hanako"]})
B = pd.DataFrame({"id": [1, 3], "score": [90, 80]})

print(pd.merge(A, B, on="id", how="inner"))
# 共通だけ(1)

print(pd.merge(A, B, on="id", how="left"))
# Aの全行(1,2)を残す。id=2はscoreがNaN

print(pd.merge(A, B, on="id", how="right"))
# Bの全行(1,3)を残す。id=3はnameがNaN

print(pd.merge(A, B, on="id", how="outer"))
# 両方の全行(1,2,3)を残す。一致しない側はNaN
Python
  • inner:両方にあるキーのみ。分析対象を共通部分に絞りたいとき。
  • left:左側を主軸に。マスタへ属性を付与する定番。
  • right:右側が主軸のとき。
  • outer:両側の全キーを残したいとき(欠損処理が前提)。

キー指定の柔軟性(複数列・異なる列名・インデックス結合)

複数列で結合(複合キー)

sales = pd.DataFrame({"store": ["A", "A", "B"], "date": ["2025-01-01", "2025-01-02", "2025-01-01"], "qty": [10, 12, 8]})
targets = pd.DataFrame({"store": ["A", "B"], "date": ["2025-01-01", "2025-01-01"], "target": [11, 9]})

out = pd.merge(sales, targets, on=["store", "date"], how="left")
print(out)
Python

複合キーで一致を厳密に取るのが安全です。日付だけ、店舗だけの結合は誤結合の元になります。

両側でキー名が異なる

left = pd.DataFrame({"user_id": [1, 2], "name": ["Taro", "Hanako"]})
right = pd.DataFrame({"id": [1, 3], "score": [90, 80]})

out = pd.merge(left, right, left_on="user_id", right_on="id", how="left")
print(out[["user_id", "name", "score"]])
Python

left_on/right_onで列名の違いを吸収できます。結合後の重複キー列(id)はdropで消すのが定石です。

インデックスで結合

L = pd.DataFrame({"name": ["Taro", "Hanako"]}, index=[1, 2])
R = pd.DataFrame({"score": [90, 80]}, index=[1, 3])

out = pd.merge(L, R, left_index=True, right_index=True, how="left")
print(out)
Python

キー列を作らず、行インデックスで突き合わせたいときに使います。


重複列・整合性チェック・結合の痕跡(suffixes・validate・indicator)

同名列の衝突を解決(suffixes)

A = pd.DataFrame({"id": [1], "value": [100]})
B = pd.DataFrame({"id": [1], "value": [120]})

out = pd.merge(A, B, on="id", how="inner", suffixes=("_left", "_right"))
print(out)
#    id  value_left  value_right
# 0   1         100          120
Python

両側に同名列があると、自動で「_x/_y」が付きます。suffixesでわかりやすい接尾辞へ変更しましょう。

結合の整合性を検証(validate)

# many_to_one(右側はキー重複なし)を期待する場合
pd.merge(A, B, on="id", how="left", validate="many_to_one")
Python

期待と違う粒度(例:右側に重複キーがあって「多対多」になった)を即座に検知できます。業務データの品質担保に有効です。

どの行が一致/不一致かを残す(indicator)

out = pd.merge(A, B, on="id", how="outer", indicator=True)
print(out[["_merge"]])
# _merge 列に 'left_only', 'right_only', 'both' が入る
Python

結合結果の由来を確認したいときに便利。欠損処理や監査の補助になります。


実践例(マスタ付与・月次売上に顧客属性を結合・時系列近傍結合)

マスタ属性を付与する定番フロー

orders = pd.DataFrame({"user_id": [1, 1, 2], "amount": [100, 200, 150]})
users  = pd.DataFrame({"id": [1, 2], "name": ["Taro", "Hanako"], "vip": [True, False]})

out = pd.merge(orders, users, left_on="user_id", right_on="id", how="left")
out = out.drop(columns=["id"])  # 使わない重複キー列は削除
print(out)
#    user_id  amount    name    vip
# 0        1     100    Taro   True
# 1        1     200    Taro   True
# 2        2     150  Hanako  False
Python

左結合で「主データ(注文)」を保ちつつ、顧客属性を付与します。重複キー列の扱いを早めに整理するのがコツ。

月次売上に店舗ターゲットを複合キーで付与

sales = pd.DataFrame({"store": ["A", "A", "B"], "month": ["2025-01", "2025-02", "2025-01"], "sales": [300, 280, 200]})
targets = pd.DataFrame({"store": ["A", "B"], "month": ["2025-01", "2025-01"], "target": [320, 220]})

out = pd.merge(sales, targets, on=["store", "month"], how="left", validate="many_to_one")
print(out)
Python

「店舗×月」をキーにすれば、誤結合を防げます。validateで右側の重複がない想定をチェック。

近い時刻で合わせる(時系列の近傍結合:asofの紹介)

# 近いタイムスタンプで合わせたいときは merge_asof を検討
# pd.merge_asof(left.sort_values("ts"), right.sort_values("ts"), on="ts", direction="nearest")
Python

ログと指標を「最も近い時点」で突き合わせるような用途では、通常のmergeではなくmerge_asofが適します(等値結合ではなく近傍結合)。


つまずき対策(誤結合・多対多・重複・型違い)

キーの前処理を必ず行う(空白・大小・型)

結合前にキー列を正規化します。文字列の空白はstr.strip、大小は揃える、数値と文字列の混在はastypeで統一。型違いは結合失敗や誤結合の原因です。

df["id"] = df["id"].astype(str).str.strip()
Python

多対多結合に注意(行が爆発する)

両側のキーが重複すると、組み合わせの分だけ行が増えます。意図したものかvalidateで確認し、必要なら重複の解消(集計して一意化)を先に行います。

同名列の衝突を見逃さない

valueやstatusのような汎用名は衝突しがち。suffixesで見分けやすくし、どちらを採用するかルール化します。不要な方はdropで確実に消します。

結合の順番を明確に(主データは左へ)

「主データ(軸)」を左に置くと、how=”left”が安定します。順序が曖昧だと、NaNの扱いがブレやすく、品質管理が難しくなります。


まとめ(on・howを軸に、前処理と整合性チェックで“安全な結合”を)

pandas.mergeは、共通キーで行を突き合わせるSQLライクな結合です。onでキーを指定し、howで結合範囲(inner/left/right/outer)を選ぶ。キー名が違えばleft_on/right_onを使い、重複列はsuffixesで整理。複数キーやインデックス結合も活用し、結合前にキーの正規化・型統一を徹底。多対多はvalidateで早期検知し、indicatorで一致状況の痕跡も確認できる。この型に沿えば、初心者でも“誤結合せず・欠損に強く・拡張しやすい”安全なデータ結合ができるようになります。

タイトルとURLをコピーしました