pandas.DataFrameを結合するmerge, join(列・インデックス基準)

Modified: | Tags: Python, pandas

共通のデータ列を持つ複数のpandas.DataFrameをその列の値に従って結合するには、pandas.merge()関数またはpandas.DataFramemerge()メソッドを使う。

インデックス列を基準にする場合はpandas.DataFramejoin()メソッドも使える。

pandas.DataFrameを縦横に連結するにはpandas.concat()関数を使う。

本記事のサンプルコードのpandasのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。以下の2つのpandas.DataFrameを例とする。

import pandas as pd

print(pd.__version__)
# 2.0.3

df_ab = pd.DataFrame({'a': ['a_1', 'a_2', 'a_3'], 'b': ['b_1', 'b_2', 'b_3']})
df_ac = pd.DataFrame({'a': ['a_1', 'a_2', 'a_4'], 'c': ['c_1', 'c_2', 'c_4']})

print(df_ab)
#      a    b
# 0  a_1  b_1
# 1  a_2  b_2
# 2  a_3  b_3

print(df_ac)
#      a    c
# 0  a_1  c_1
# 1  a_2  c_2
# 2  a_4  c_4

pd.merge(), pd.DataFrame.merge()の基本的な使い方

pd.merge()関数では、第一引数leftと第二引数rightに結合する2つのpandas.DataFrameを指定する。

print(pd.merge(df_ab, df_ac))
#      a    b    c
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2

merge()メソッドの場合は、leftに相当するpandas.DataFrameからメソッドを呼び出し、rightに相当するpandas.DataFrameを引数に指定する。

print(df_ab.merge(df_ac))
#      a    b    c
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2

どちらも結合された新たなpandas.DataFrameを返す。

以降で説明する引数はpd.merge()関数でもmerge()メソッドでも共通。

キーとする列を指定: 引数on, left_on, right_on

デフォルトでは、2つのpandas.DataFrameに共通する列名の列をキーとして結合処理が行われる。

キーとする列名を明示的に指定するには引数onを使う。省略して問題ない場合も明示しておいたほうが分かりやすい。

print(pd.merge(df_ab, df_ac, on='a'))
#      a    b    c
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2

引数left_on, right_onで、それぞれのpandas.DataFrameでキーとする列名を別々に指定することも可能。

df_ac_ = df_ac.rename(columns={'a': 'a_'})
print(df_ac_)
#     a_    c
# 0  a_1  c_1
# 1  a_2  c_2
# 2  a_4  c_4

print(pd.merge(df_ab, df_ac_, left_on='a', right_on='a_'))
#      a    b   a_    c
# 0  a_1  b_1  a_1  c_1
# 1  a_2  b_2  a_2  c_2

この場合、両方の列が残るので、必要ない場合はdrop()メソッドで削除する。

print(pd.merge(df_ab, df_ac_, left_on='a', right_on='a_').drop(columns='a_'))
#      a    b    c
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2

on, left_on, right_onに列名のリストを指定して複数の列をキーとすることもできる。後述。

結合方法を指定: 引数how

結合方法は引数howに文字列で指定する。デフォルトはhow='inner'

データがない要素は欠損値NaNとなる。欠損値NaNの処理については以下の記事を参照。

内部結合(INNER JOIN): how='inner'

leftright両方のDataFrameに共通するキーを持つ行が残る。これがデフォルト。

print(pd.merge(df_ab, df_ac, on='a', how='inner'))
#      a    b    c
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2

左結合(LEFT JOIN): how='left'

leftを基準に結合。rightにキーが存在しない行も残る。左外部結合とも呼ばれる。

print(pd.merge(df_ab, df_ac, on='a', how='left'))
#      a    b    c
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2
# 2  a_3  b_3  NaN

右結合(RIGHT JOIN): how='right'

rightを基準に結合。leftにキーが存在しない行も残る。右外部結合とも呼ばれる。

print(pd.merge(df_ab, df_ac, on='a', how='right'))
#      a    b    c
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2
# 2  a_4  NaN  c_4

外部結合(OUTER JOIN): how='outer'

leftrightのすべての行が残る。完全外部結合とも呼ばれる。

print(pd.merge(df_ab, df_ac, on='a', how='outer'))
#      a    b    c
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2
# 2  a_3  b_3  NaN
# 3  a_4  NaN  c_4

交差結合(CROSS JOIN): how='cross'

leftrightのすべての組み合わせを生成して結合する。デフォルトでは列名に_x, _yというサフィックス(接尾辞)が付く。後述の引数suffixesで指定可能。

print(pd.merge(df_ab, df_ac, how='cross'))
#    a_x    b  a_y    c
# 0  a_1  b_1  a_1  c_1
# 1  a_1  b_1  a_2  c_2
# 2  a_1  b_1  a_4  c_4
# 3  a_2  b_2  a_1  c_1
# 4  a_2  b_2  a_2  c_2
# 5  a_2  b_2  a_4  c_4
# 6  a_3  b_3  a_1  c_1
# 7  a_3  b_3  a_2  c_2
# 8  a_3  b_3  a_4  c_4

how='cross'のときは引数onleft_on, right_onを指定するとエラーになる。

# print(pd.merge(df_ab, df_ac, on='a', how='cross'))
# MergeError: Can not pass on, right_on, left_on or set right_index=True or left_index=True

データの情報を取得: 引数indicator

引数indicatorTrueとすると、元データの情報を含む列が追加される。

デフォルトでは_mergeという名前の列が追加され、both, left_only, right_onlyのいずれかに分類される。

print(pd.merge(df_ab, df_ac, on='a', how='inner', indicator=True))
#      a    b    c _merge
# 0  a_1  b_1  c_1   both
# 1  a_2  b_2  c_2   both

print(pd.merge(df_ab, df_ac, on='a', how='outer', indicator=True))
#      a    b    c      _merge
# 0  a_1  b_1  c_1        both
# 1  a_2  b_2  c_2        both
# 2  a_3  b_3  NaN   left_only
# 3  a_4  NaN  c_4  right_only

_mergeではない任意の列名にしたい場合は引数indicatorに文字列を指定する。

print(pd.merge(df_ab, df_ac, on='a', how='outer', indicator='indicator'))
#      a    b    c   indicator
# 0  a_1  b_1  c_1        both
# 1  a_2  b_2  c_2        both
# 2  a_3  b_3  NaN   left_only
# 3  a_4  NaN  c_4  right_only

列名が重複している場合のサフィックスを指定: 引数suffixes

leftrightでキーにする列以外の列名が重複している場合、デフォルトでは_x, _yというサフィックス(接尾辞)がつけられる。

df_ac_b = df_ac.rename(columns={'c': 'b'})
print(df_ac_b)
#      a    b
# 0  a_1  c_1
# 1  a_2  c_2
# 2  a_4  c_4

print(pd.merge(df_ab, df_ac_b, on='a'))
#      a  b_x  b_y
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2

任意のサフィックスをつけたい場合は、引数suffixes[left用サフィックス, right用サフィックス]のように2つの要素のリストやタプルを指定する。

print(pd.merge(df_ab, df_ac_b, on='a', suffixes=['_left', '_right']))
#      a b_left b_right
# 0  a_1    b_1     c_1
# 1  a_2    b_2     c_2

複数の列をキーとする場合

これまでの例はキーとする列が一列だけだったが、複数の列をキーとすることもできる。

列を追加したpandas.DataFrameを例とする。

df_abx = df_ab.assign(x=['x_2', 'x_2', 'x_3'])
df_acx = df_ac.assign(x=['x_1', 'x_2', 'x_2'])

print(df_abx)
#      a    b    x
# 0  a_1  b_1  x_2
# 1  a_2  b_2  x_2
# 2  a_3  b_3  x_3

print(df_acx)
#      a    c    x
# 0  a_1  c_1  x_1
# 1  a_2  c_2  x_2
# 2  a_4  c_4  x_2

共通する列名の列が複数存在する場合、デフォルトですべての列がキーとして処理される。明示的に指定する場合は引数onに列名のリストを指定する。

print(pd.merge(df_abx, df_acx))
#      a    b    x    c
# 0  a_2  b_2  x_2  c_2

print(pd.merge(df_abx, df_acx, on=['a', 'x']))
#      a    b    x    c
# 0  a_2  b_2  x_2  c_2

共通する列名の列が複数存在していても片方の列のみをキーとすることもできる。重複する列名にはサフィックスがつけられる。上述のように引数suffixesで任意のサフィックスを指定可能。

print(pd.merge(df_abx, df_acx, on='a'))
#      a    b  x_x    c  x_y
# 0  a_1  b_1  x_2  c_1  x_1
# 1  a_2  b_2  x_2  c_2  x_2

異なる列名の列をキーとする場合は引数left_on, right_onにそれぞれ列名のリストを指定する。

df_acx_ = df_acx.rename(columns={'x': 'x_'})
print(df_acx_)
#      a    c   x_
# 0  a_1  c_1  x_1
# 1  a_2  c_2  x_2
# 2  a_4  c_4  x_2

print(pd.merge(df_abx, df_acx_, left_on=['a', 'x'], right_on=['a', 'x_']))
#      a    b    x    c   x_
# 0  a_2  b_2  x_2  c_2  x_2

引数howも単独の列をキーとするときと同様に指定可能。

print(pd.merge(df_abx, df_acx, on=['a', 'x'], how='inner'))
#      a    b    x    c
# 0  a_2  b_2  x_2  c_2

print(pd.merge(df_abx, df_acx, on=['a', 'x'], how='left'))
#      a    b    x    c
# 0  a_1  b_1  x_2  NaN
# 1  a_2  b_2  x_2  c_2
# 2  a_3  b_3  x_3  NaN

print(pd.merge(df_abx, df_acx, on=['a', 'x'], how='right'))
#      a    b    x    c
# 0  a_1  NaN  x_1  c_1
# 1  a_2  b_2  x_2  c_2
# 2  a_4  NaN  x_2  c_4

print(pd.merge(df_abx, df_acx, on=['a', 'x'], how='outer'))
#      a    b    x    c
# 0  a_1  b_1  x_2  NaN
# 1  a_2  b_2  x_2  c_2
# 2  a_3  b_3  x_3  NaN
# 3  a_1  NaN  x_1  c_1
# 4  a_4  NaN  x_2  c_4

print(pd.merge(df_abx, df_acx, how='cross'))
#    a_x    b  x_x  a_y    c  x_y
# 0  a_1  b_1  x_2  a_1  c_1  x_1
# 1  a_1  b_1  x_2  a_2  c_2  x_2
# 2  a_1  b_1  x_2  a_4  c_4  x_2
# 3  a_2  b_2  x_2  a_1  c_1  x_1
# 4  a_2  b_2  x_2  a_2  c_2  x_2
# 5  a_2  b_2  x_2  a_4  c_4  x_2
# 6  a_3  b_3  x_3  a_1  c_1  x_1
# 7  a_3  b_3  x_3  a_2  c_2  x_2
# 8  a_3  b_3  x_3  a_4  c_4  x_2

インデックスをキーに指定: 引数left_index, right_index

インデックス(行名・行ラベル)をキーに指定するには、引数left_index, right_indexTrueとする。

引数left_on, right_onと組み合わせることが可能。

df_ac_i = df_ac.set_index('a')
print(df_ac_i)
#        c
# a       
# a_1  c_1
# a_2  c_2
# a_4  c_4

print(pd.merge(df_ab, df_ac_i, left_on='a', right_index=True))
#      a    b    c
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2

引数left_index, right_indexを両方ともTrueとしてもよい。

df_ab_i = df_ab.set_index('a')
print(df_ab_i)
#        b
# a       
# a_1  b_1
# a_2  b_2
# a_3  b_3

print(pd.merge(df_ab_i, df_ac_i, left_index=True, right_index=True))
#        b    c
# a            
# a_1  b_1  c_1
# a_2  b_2  c_2

インデックスをキーにする場合は次に示すjoin()メソッドを使うこともできる。

pd.DataFrame.join()の基本的な使い方

インデックスをキーとして結合するには、pandas.DataFramejoin()メソッドを使うこともできる。pandas.join()関数は提供されていない。使い方は概ねmerge()と同じ。

インデックスを設定したpandas.DataFrameを例とする。

print(df_ab_i)
#        b
# a       
# a_1  b_1
# a_2  b_2
# a_3  b_3

print(df_ac_i)
#        c
# a       
# a_1  c_1
# a_2  c_2
# a_4  c_4

引数how

join()はインデックスをキーとして結合する。

merge()と異なり、左結合(how='left')がデフォルト。呼び出し元のpandas.DataFrameleft、引数に指定するpandas.DataFramerightに対応する。

print(df_ab_i.join(df_ac_i))
#        b    c
# a            
# a_1  b_1  c_1
# a_2  b_2  c_2
# a_3  b_3  NaN

print(df_ab_i.join(df_ac_i, how='inner'))
#        b    c
# a            
# a_1  b_1  c_1
# a_2  b_2  c_2

print(df_ab_i.join(df_ac_i, how='left'))
#        b    c
# a            
# a_1  b_1  c_1
# a_2  b_2  c_2
# a_3  b_3  NaN

print(df_ab_i.join(df_ac_i, how='right'))
#        b    c
# a            
# a_1  b_1  c_1
# a_2  b_2  c_2
# a_4  NaN  c_4

print(df_ab_i.join(df_ac_i, how='outer'))
#        b    c
# a            
# a_1  b_1  c_1
# a_2  b_2  c_2
# a_3  b_3  NaN
# a_4  NaN  c_4

print(df_ab_i.join(df_ac_i, how='cross'))
#      b    c
# 0  b_1  c_1
# 1  b_1  c_2
# 2  b_1  c_4
# 3  b_2  c_1
# 4  b_2  c_2
# 5  b_2  c_4
# 6  b_3  c_1
# 7  b_3  c_2
# 8  b_3  c_4

引数on

呼び出し元のpandas.DataFrameのキーとする列を引数onで指定できる。引数に指定するpandas.DataFrameは常にインデックスがキーとなる。

print(df_ab)
#      a    b
# 0  a_1  b_1
# 1  a_2  b_2
# 2  a_3  b_3

print(df_ab.join(df_ac_i, on='a'))
#      a    b    c
# 0  a_1  b_1  c_1
# 1  a_2  b_2  c_2
# 2  a_3  b_3  NaN

引数lsuffix, rsuffix

結果に重複する列名がある場合、デフォルトではエラーとなる。引数lsuffixrsuffixを指定する必要がある。

df_ab_i2 = df_ac_i.rename(columns={'c': 'b'})
print(df_ab_i2)
#        b
# a       
# a_1  c_1
# a_2  c_2
# a_4  c_4

# print(df_ab_i.join(df_ab_i2))
# ValueError: columns overlap but no suffix specified: Index(['b'], dtype='object')

print(df_ab_i.join(df_ab_i2, lsuffix='_left', rsuffix='_right'))
#     b_left b_right
# a                 
# a_1    b_1     c_1
# a_2    b_2     c_2
# a_3    b_3     NaN

複数のpandas.DataFrameをリストで指定

join()の第一引数にはpandas.DataFrameのリストを指定することも可能。

df_ad_i = pd.DataFrame({'a': ['a_1', 'a_4', 'a_5'], 'd': ['d_1', 'd_4', 'd_5']}).set_index('a')
print(df_ad_i)
#        d
# a       
# a_1  d_1
# a_4  d_4
# a_5  d_5

print(df_ab_i.join([df_ac_i, df_ad_i]))
#        b    c    d
# a                 
# a_1  b_1  c_1  d_1
# a_2  b_2  c_2  NaN
# a_3  b_3  NaN  NaN

print(df_ac_i.join([df_ad_i, df_ab_i]))
#        c    d    b
# a                 
# a_1  c_1  d_1  b_1
# a_2  c_2  NaN  b_2
# a_4  c_4  d_4  NaN

関連カテゴリー

関連記事