【Pandas】merge・concatで複数のデータを結合する

Pandas

こんにちは、かつコーチです。
実務のデータ分析では、1つのファイルだけで完結することはほとんどなく、「売上データ」と「顧客マスタ」のように複数のデータを組み合わせる場面が必ず出てきます。
この記事では、データ結合の代表的な方法であるmergeconcatの違いと使い分けを解説します。

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_onright_onを指定します。

orders2 = pd.DataFrame({
    "顧客番号": [1, 2],
    "商品": ["りんご", "みかん"]
})

merged = pd.merge(customers, orders2, left_on="顧客ID", right_on="顧客番号")

つまずきやすい設定・注意点

  • how="inner"(デフォルト)は、両方に存在するデータしか残らないため、意図せずデータが減っていることに気づきにくい
  • キーの列に表記ゆれ(全角/半角、空白の有無)があると、本来一致するはずのデータが一致せず結合漏れが発生する

merge・concatの使い分け早見表

観点concatmerge
主な用途同じ形式のデータを積み重ねる異なるデータを共通キーで紐づける
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が混在しており、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, 中級者向け, データ加工

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