こんにちは、かつコーチです。
実務のデータ分析では、1つのファイルだけで完結することはほとんどなく、「売上データ」と「顧客マスタ」のように複数のデータを組み合わせる場面が必ず出てきます。
この記事では、データ結合の代表的な方法であるmergeとconcatの違いと使い分けを解説します。
mergeとconcatとは?
concatの定義:単純に積み重ねる・並べる
concatとは、複数のDataFrameを単純に縦(行方向)や横(列方向)につなげるための関数です。
SQLでいうUNIONに近いイメージです。
import pandas as pd
df1 = pd.DataFrame({"名前": ["田中", "佐藤"], "点数": [80, 90]})
df2 = pd.DataFrame({"名前": ["鈴木", "高橋"], "点数": [70, 85]})
df_concat = pd.concat([df1, df2], ignore_index=True)
print(df_concat)
名前 点数
0 田中 80
1 佐藤 90
2 鈴木 70
3 高橋 85
mergeの定義:共通の列をキーに結合する
mergeとは、共通の列(キー)の値をもとに、2つのDataFrameを横方向に結合するための関数です。
SQLでいうJOINに相当します。
customers = pd.DataFrame({
"顧客ID": [1, 2, 3],
"名前": ["田中", "佐藤", "鈴木"]
})
orders = pd.DataFrame({
"顧客ID": [1, 2, 2],
"商品": ["りんご", "みかん", "ぶどう"]
})
merged = pd.merge(customers, orders, on="顧客ID")
print(merged)
顧客ID 名前 商品
0 1 田中 りんご
1 2 佐藤 みかん
2 2 佐藤 ぶどう
顧客マスタと注文データを、「顧客ID」というキーで結びつけています。
なぜ両方を理解する必要があるのか
「同じ形式のデータを追加したいだけ」なのか「別々のデータを共通キーで紐づけたい」のかによって、使うべき関数がまったく異なります。
この違いを理解していないと、本来mergeを使うべき場面でconcatを使ってしまい、意図しない形でデータが並んでしまう、といったミスにつながります。
基本の書き方:merge・concatの使い方
手順1:concatで縦方向に結合する
月ごとに分かれたCSVファイルを1つにまとめる、といった場面でよく使います。
jan = pd.read_csv("sales_jan.csv")
feb = pd.read_csv("sales_feb.csv")
df_all = pd.concat([jan, feb], ignore_index=True)
ignore_index=Trueをつけないと、結合後もそれぞれの元のインデックスが残ってしまい、0, 1, 2, 0, 1のように重複したインデックスになります。
手順2:concatで横方向に結合する
axis=1を指定すると、列を横に並べる結合になります。
df_side = pd.concat([df1, df2], axis=1)
ただし横方向の結合は行の対応関係がずれやすいため、実務では次に説明するmergeを使う方が安全なケースが多いです。
手順3:mergeの結合方法(how引数)を使い分ける
mergeにはhow引数があり、SQLのJOINと同じように結合方法を選べます。
# 両方に存在するデータだけ結合(デフォルト)
pd.merge(customers, orders, on="顧客ID", how="inner")
# 左側(customers)を軸にして、対応する注文がなければNaN
pd.merge(customers, orders, on="顧客ID", how="left")
# 右側(orders)を軸にして結合
pd.merge(customers, orders, on="顧客ID", how="right")
# どちらか一方にでも存在すればすべて結合
pd.merge(customers, orders, on="顧客ID", how="outer")
手順4:キーの列名が異なる場合の結合
キーとなる列名が2つのDataFrameで異なる場合は、left_on・right_onを指定します。
orders2 = pd.DataFrame({
"顧客番号": [1, 2],
"商品": ["りんご", "みかん"]
})
merged = pd.merge(customers, orders2, left_on="顧客ID", right_on="顧客番号")
つまずきやすい設定・注意点
how="inner"(デフォルト)は、両方に存在するデータしか残らないため、意図せずデータが減っていることに気づきにくい- キーの列に表記ゆれ(全角/半角、空白の有無)があると、本来一致するはずのデータが一致せず結合漏れが発生する
merge・concatの使い分け早見表
| 観点 | concat | merge |
|---|---|---|
| 主な用途 | 同じ形式のデータを積み重ねる | 異なるデータを共通キーで紐づける |
| SQLでの対応 | UNIONに近い | JOINに近い |
| キーの指定 | 不要 | 必要(onで指定) |
| 代表例 | 月別CSVの結合、複数店舗データの統合 | 顧客マスタと注文データの結合 |
迷ったときは「同じ種類のデータを積み増すだけならconcat」「違う種類のデータをキーで結びつけるならmerge」と覚えておくとシンプルです。
よくあるつまずきポイント・エラー対処
how=”inner”のせいでデータが消えたように見える
❌Before:howを意識せずデフォルト(inner)のまま結合し、件数が減っていることに気づかない
merged = pd.merge(customers, orders, on="顧客ID")
print(len(customers), len(orders), len(merged))
私が実際にこの状況に遭遇したのは、顧客マスタと注文データを結合したところ、結合後の件数が明らかに少なくなっていたときです。
原因を調べると、顧客ID側に全角の1、注文データ側に半角の1が混在しており、inner結合で一致しなかった行が黙って除外されていました。
エラーは出ないため、件数を確認しない限り気づけないタイプのミスです。
✅After:結合前後の件数を必ず確認し、意図的にhow="left"などを使い分ける
merged = pd.merge(customers, orders, on="顧客ID", how="left")
print(f"結合前: {len(customers)}件 / 結合後: {len(merged)}件")
# 結合できなかった行(NaNになった行)を確認する
unmatched = merged[merged["商品"].isnull()]
print(unmatched)
「結合したら必ず件数を確認する」という習慣が、この種のミスを未然に防いでくれます。
応用・一歩先の使い方
結合したキーの由来を確認する(indicator引数)
indicator=Trueを指定すると、各行がどちらのデータ由来かを示す列が追加され、結合漏れの調査に役立ちます。
merged = pd.merge(customers, orders, on="顧客ID", how="outer", indicator=True)
print(merged)
_merge列にboth(両方に存在)、left_only(左側のみ)、right_only(右側のみ)が表示されます。
複数のキーで結合する
「都道府県」と「年月」の組み合わせで結合したい、といったケースでは、onにリストを渡します。
merged = pd.merge(df1, df2, on=["都道府県", "年月"])
まとめ
この記事のポイント
concatは同じ形式のデータを単純に積み重ねる(縦・横)mergeは共通キーをもとに異なるデータを結合する(SQLのJOINに相当)how引数(inner/left/right/outer)の選択で、結合結果の件数が大きく変わる- 結合後は必ず件数を確認し、意図しないデータ欠落がないかチェックする
indicator=Trueを使うと、結合できなかった行の調査がしやすくなる
次に読むべき記事
複数データの結合ができるようになったら、次は集計・加工したデータを目で見て確認する「pandasの標準機能でグラフを作成する(plot基本)」に進みましょう。
数値の表だけでは気づきにくい傾向も、グラフにすると一目で分かるようになります。
タグ: Pandas, 中級者向け, データ加工