17
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

pandasでデータを結合していく【concat、merge、joinの違い】

Last updated at Posted at 2023-02-25

はじめに

ググれば多量に出てくる話ではありますが、
pandasでデータを結合する際に出てくる、concat、merge、joinについて
正しく理解をするのは、pythonでデータを扱う第一歩です。

特にSQLは慣れているけれど、
Pyhton、pandasを使うのは初めて、という人からすると、
以下の感覚になるはずです。

  • concatって、文字列どうしを結合する話ではないの?
  • mergeって、あるテーブルから他のテーブルに、insertやupdateを行う話ではないの?
  • joinはまさしく、2つのテーブルを条件に合う形で結合する処理だよね

一方pandasだとそうではなく。それぞれを正しく理解していく必要があります。

結論

  • concat:単にくっつけるイメージ、縦にも横にも結合可能、その結果細かい結合ができない
  • merge:「データ」を軸に横に結合。何を軸に結合するかを意識しつつ利用。
  • join:「インデックス」を軸に横に結合。結合軸がインデックスで固定のため、複数をまとめ結合できる

concat

concatは、
「同じ構造のテーブルが、複数のCSVに分かれて保存されているけれど
 それを一つにくっつけて、扱いやすいようにしよう」
という目的で使うようなイメージが正しいです。

複数のデータフレームを縦方向または横方向に結合する手段です。
横にも縦にも結合できます。

後述するmergeやjoinと区別する意味合いでも、
concatは「単にくっつける」もの。と理解するといいでしょう。
複雑なくっつけ方を求める場合は他の手段を使う必要があります。

Python
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")

シンプルに縦方向結合

Python
pd.concat([df1, df2])

image.png

axis指定で横方向結合

Python
pd.concat([df1, df3], axis=1)

image.png

異なるカラムを持つ要素同士を結合

Python
pd.concat([df1, df4])

image.png

Python
pd.concat([df1, df4], axis=1)

image.png

内部結合

一方でもデータがないものは削除する

Python
pd.concat([df1, df4], axis=1, join='inner')

image.png

concatでは右結合、左結合はできません。

結合軸(インデックス)以外は同名でも別物として扱う

Python
pd.concat([df1, df2], axis=1)

image.png

merge

mergeは、データ側(インデックスではない)を軸に横方向の結合を行います。

concatは単にくっつける形で、分割されていたデータを合体させていくイメージでした。
指定次第で横にも縦にも結合できました。
(但し、右結合や左結合ができない等、万能ではありません)

mergeは「データ」を軸に、横方向結合に特化しています。
concatでも横方向結合はできましたが、横方向結合だけでいえばmergeのほうができることが多くなります。

後述のjoinは「インデックス」を軸にした結合となる点が違いです。
mergeはデータが軸となるため、どこが結合の軸となるか?を意識しながら利用します。

Python
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を作成する

Python
df1.merge(df2)

image.png

「共通する列名」をキーとして結合処理が行われる。

この場合、df1を「上書き」するのではなく、
結果を新たなDFとして生成しています。
なのでこの直後にdf1を確認しても、元のデータのままです。

Python
df1.head()

image.png

書き方2:mergeの引数にd1,d1を含め、新たなDFを作成する

Python
pd.merge(df1, df2)

image.png

書き方1と結果は同様

複数列の名称が同じ場合のmerge

Python
df1.merge(df3)

image.png

複数列が同じ場合、同じ名称の列すべてを対象に、同一の列をマージする。
そのため、今回の例では A-りんご のみ残る。

結合列の明示的な指定

Python
df1.merge(df3, on='Shop')

image.png

on で結合時の列を指定できる。
同一名の列が1つしかない場合は、onを指定してもしなくても結果は同じ。
同一名の列が2つ以上ある場合結果が変わる。
この時、他の同一名列に関しては、名称が例のように補完される。

結合方法

  1. 内部結合:how='inner' (※何もつけない時と同じ)

    Python
    pd.merge(df1, df4, how='inner')
    

    image.png

  2. 外部結合:how='outer'

    Python
    pd.merge(df1, df4, how='outer')
    

    image.png

  3. 左結合:how='left'

    Python
    pd.merge(df1, df4, how='left')
    

    image.png

  4. 左結合:how='right'

    Python
    pd.merge(df1, df4, how='right')
    

    image.png

mergeの重要な特徴として、1度に結合できるのは2つまでという点です。
concatは3つ以上の結合が可能です
 例)pd.concat([df1, df2, df3])
ですが、mergeではこのような記載はできません。

join

joinは、インデックス(データではない)を軸に、横方向の結合を行います。

joinは「インデックス」を軸にした結合です。
つまり同一のインデックスでないと結合できません。
(※厳密には、左側のデータはインデックス以外を指定することも可能ですが、右側はインデックスが軸になります)
mergeはデータを軸とするためある意味では汎用的ですが、一度に3つ以上の結合を行うことはできませんでした。
joinはインデックスが軸となるため、一度に3つ以上の結合が可能となります。

concatとの違いはmergeと同様、
concatは単に結合するイメージ、縦にも横にも結合可能でしたが、その結果細かい結合ができませんでした。
joinは横方向特化のため、concatより細かい結合が可能です。

Python
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を作成する

Python
df1.join(df2)

image.png

mergeの時にできた以下のような記述は、joinではできません。

Python
#mergeでできた以下のような記載はできない
pd.join(df1, df2)
AttributeError: module 'pandas' has no attribute 'join'

結合列の明示的な指定(※左側のみ)

Python
# 左側であるdf3について、結合列をonで指定することが可能
# 右側であるdf1は指定できず、インデックスが利用される
df3.join(df1, on="Shop")

image.png

3つ以上の一括結合

Python
df1.join([df2, df4])

image.png

結合方法 → mergeとデフォルト値が異なる

  1. 内部結合:how='inner' 

    Python
    df1.join(df2, how='inner')
    

    image.png

  2. 外部結合:how='outer'

    Python
    df1.join(df2, how='outer')
    

    image.png

  3. 左結合:how='left' (※何もつけない時と同じ)

    Python
    df1.join(df2, how='left')
    

    image.png

  4. 左結合:how='right'

    Python
    df1.join(df2, how='right')
    

    image.png

まとめ

  • concat:単にくっつけるイメージ、縦にも横にも結合可能、その結果細かい結合ができない
  • merge:「データ」を軸に横に結合。何を軸に結合するかを意識しつつ利用。
  • join:「インデックス」を軸に横に結合。結合軸がインデックスで固定のため、複数をまとめ結合できる
17
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?