概要(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
Pythonleft(左外部結合)は左側(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"]])
Pythonleft_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で一致状況の痕跡も確認できる。この型に沿えば、初心者でも“誤結合せず・欠損に強く・拡張しやすい”安全なデータ結合ができるようになります。
