はじめに
ググれば多量に出てくる話ではありますが、
pandasでデータを結合する際に出てくる、concat、merge、joinについて
正しく理解をするのは、pythonでデータを扱う第一歩です。
特にSQLは慣れているけれど、
Pyhton、pandasを使うのは初めて、という人からすると、
以下の感覚になるはずです。
- concatって、文字列どうしを結合する話ではないの?
- mergeって、あるテーブルから他のテーブルに、insertやupdateを行う話ではないの?
- joinはまさしく、2つのテーブルを条件に合う形で結合する処理だよね
一方pandasだとそうではなく。それぞれを正しく理解していく必要があります。
結論
- concat:単にくっつけるイメージ、縦にも横にも結合可能、その結果細かい結合ができない
- merge:「データ」を軸に横に結合。何を軸に結合するかを意識しつつ利用。
- join:「インデックス」を軸に横に結合。結合軸がインデックスで固定のため、複数をまとめ結合できる
concat
concatは、
「同じ構造のテーブルが、複数のCSVに分かれて保存されているけれど
それを一つにくっつけて、扱いやすいようにしよう」
という目的で使うようなイメージが正しいです。
複数のデータフレームを縦方向または横方向に結合する手段です。
横にも縦にも結合できます。
後述するmergeやjoinと区別する意味合いでも、
concatは「単にくっつける」もの。と理解するといいでしょう。
複雑なくっつけ方を求める場合は他の手段を使う必要があります。
import pandas as pd
df1 = pd.DataFrame({"Name": ["田中", "鈴木", "柴田"],
"Group": ["A", "A", "B"],
"Point": [1, 2, 2]}).set_index("Name")
df2 = pd.DataFrame({"Name": ["松井", "広末"],
"Group": ["A", "C"],
"Point": [0, 3]}).set_index("Name")
df3 = pd.DataFrame({"Name": ["田中", "鈴木", "柴田"],
"Address": ["東京", "大阪", "北海道"]}).set_index("Name")
df4 = pd.DataFrame({"Name": ["田中", "鈴木", "大井"],
"Address": ["東京", "大阪", "福岡"]}).set_index("Name")
シンプルに縦方向結合
pd.concat([df1, df2])
axis指定で横方向結合
pd.concat([df1, df3], axis=1)
異なるカラムを持つ要素同士を結合
pd.concat([df1, df4])
pd.concat([df1, df4], axis=1)
内部結合
一方でもデータがないものは削除する
pd.concat([df1, df4], axis=1, join='inner')
concatでは右結合、左結合はできません。
結合軸(インデックス)以外は同名でも別物として扱う
pd.concat([df1, df2], axis=1)
merge
mergeは、データ側(インデックスではない)を軸に横方向の結合を行います。
concatは単にくっつける形で、分割されていたデータを合体させていくイメージでした。
指定次第で横にも縦にも結合できました。
(但し、右結合や左結合ができない等、万能ではありません)
mergeは「データ」を軸に、横方向結合に特化しています。
concatでも横方向結合はできましたが、横方向結合だけでいえばmergeのほうができることが多くなります。
後述のjoinは「インデックス」を軸にした結合となる点が違いです。
mergeはデータが軸となるため、どこが結合の軸となるか?を意識しながら利用します。
import pandas as pd
df1 = pd.DataFrame({"Shop":["A", "A", "B", "C"],
"Item":["りんご", "みかん", "ぶどう", "りんご"]})
df2 = pd.DataFrame({"Item":["りんご", "みかん", "ぶどう"],
"price":[150, 300, 500]})
df3 = pd.DataFrame({"Shop":["A", "D", "E"],
"Item":["りんご", "りんご", "なし"]})
df4 = pd.DataFrame({"Shop":["A","B","D"],
"Location":["東京", "大阪", "北海道"]})
書き方1:df1に対しdf2をmergeし、新たなDFを作成する
df1.merge(df2)
「共通する列名」をキーとして結合処理が行われる。
書き方2:mergeの引数にd1,d1を含め、新たなDFを作成する
pd.merge(df1, df2)
書き方1と結果は同様
複数列の名称が同じ場合のmerge
df1.merge(df3)
複数列が同じ場合、同じ名称の列すべてを対象に、同一の列をマージする。
そのため、今回の例では A-りんご のみ残る。
結合列の明示的な指定
df1.merge(df3, on='Shop')
on で結合時の列を指定できる。
同一名の列が1つしかない場合は、onを指定してもしなくても結果は同じ。
同一名の列が2つ以上ある場合結果が変わる。
この時、他の同一名列に関しては、名称が例のように補完される。
結合方法
-
内部結合:how='inner' (※何もつけない時と同じ)
Pythonpd.merge(df1, df4, how='inner')
-
外部結合:how='outer'
Pythonpd.merge(df1, df4, how='outer')
-
左結合:how='left'
Pythonpd.merge(df1, df4, how='left')
-
左結合:how='right'
Pythonpd.merge(df1, df4, how='right')
mergeの重要な特徴として、1度に結合できるのは2つまでという点です。
concatは3つ以上の結合が可能です
例)pd.concat([df1, df2, df3])
ですが、mergeではこのような記載はできません。
join
joinは、インデックス(データではない)を軸に、横方向の結合を行います。
joinは「インデックス」を軸にした結合です。
つまり同一のインデックスでないと結合できません。
(※厳密には、左側のデータはインデックス以外を指定することも可能ですが、右側はインデックスが軸になります)
mergeはデータを軸とするためある意味では汎用的ですが、一度に3つ以上の結合を行うことはできませんでした。
joinはインデックスが軸となるため、一度に3つ以上の結合が可能となります。
concatとの違いはmergeと同様、
concatは単に結合するイメージ、縦にも横にも結合可能でしたが、その結果細かい結合ができませんでした。
joinは横方向特化のため、concatより細かい結合が可能です。
import pandas as pd
df1 = pd.DataFrame({"Shop":["A", "A", "B", "C"],
"Fruit":["りんご", "みかん", "ぶどう", "りんご"]}).set_index("Shop")
df2 = pd.DataFrame({"Shop":["A", "B", "D"],
"Meat":["牛", "豚", "牛"]}).set_index('Shop')
df3 = pd.DataFrame({"ID":["1", "2", "3", "4", "5"],
"Shop":["A", "B", "C", "D", "E"],
"Location":["東京", "大阪", "北海道", "愛知", "福岡"]}).set_index('ID')
df4 = pd.DataFrame({"Shop":["B", "D"],
"Drink":["お茶", "コーラ"]}).set_index('Shop')
書き方:df1に対しdf2をjoinし、新たなDFを作成する
df1.join(df2)
mergeの時にできた以下のような記述は、joinではできません。
#mergeでできた以下のような記載はできない
pd.join(df1, df2)
AttributeError: module 'pandas' has no attribute 'join'
結合列の明示的な指定(※左側のみ)
# 左側であるdf3について、結合列をonで指定することが可能
# 右側であるdf1は指定できず、インデックスが利用される
df3.join(df1, on="Shop")
3つ以上の一括結合
df1.join([df2, df4])
結合方法 → mergeとデフォルト値が異なる
-
内部結合:how='inner'
Pythondf1.join(df2, how='inner')
-
外部結合:how='outer'
Pythondf1.join(df2, how='outer')
-
左結合:how='left' (※何もつけない時と同じ)
Pythondf1.join(df2, how='left')
-
左結合:how='right'
Pythondf1.join(df2, how='right')
まとめ
- concat:単にくっつけるイメージ、縦にも横にも結合可能、その結果細かい結合ができない
- merge:「データ」を軸に横に結合。何を軸に結合するかを意識しつつ利用。
- join:「インデックス」を軸に横に結合。結合軸がインデックスで固定のため、複数をまとめ結合できる