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

日付や名前などの共通のデータ列を持っている複数のpandas.DataFrameをその列の値に従って結合するにはpandas.merge()関数またはpandas.DataFrameのmerge()メソッドを使います。

pandas.merge — pandas 0.23.3 documentation pandas.DataFrame.merge — pandas 0.23.3 documentation

インデックス列を基準にする場合はpandas.merge()関数も使えるし、pandas.DataFrameのjoin()メソッドも使える。

pandas.DataFrame.join — pandas 0.23.3 documentation

ここでは以下の内容について説明します。

pd.merge(), pd.DataFrame.merge()の基本的な使い方 キーとする列を指定: 引数on, left_on, right_on 結合方法を指定: 引数how 内部結合(inner_join): how='inner' 左結合(left_join): how='left' 右結合(right_join): how='right' 外部結合(outer_join): how='outer'

データの情報を取得: 引数indicator 列名が重複している場合のサフィックスを指定: 引数suffixes 複数の列をキーとする場合 キー列でソート: 引数sort インデックスをキーに指定: 引数left_index, right_index pd.DataFrame.join()の基本的な使い方

以下の2つのpandas.DataFrameを例とします。

import pandas as pd

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

なお、pandas.DataFrameを縦横に連結するにはpandas.concat()関数を使います。以下の記事を参照。

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

この場合、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'

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'

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'

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'

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

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

引数indicatorをTrueとすると、元データの情報を含む列が追加される。 デフォルトでは_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

leftとrightでキーにする列以外の列名が重複している場合、デフォルトでは_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用サフィックス]というリストやタプルを指定します。

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

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

これまでの例はキーとする列が一列だけだった。複数の列をキーとしたい場合について説明します。 以下の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

共通する列名の列が複数存在していても片方の列のみをキーとすることも可能。上の例のようにサフィックスがつけられる。

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_2  b_2  x_2  c_2
# 1  a_1  NaN  x_1  c_1
# 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

キー列でソート: 引数sort

キー列でソートする場合は引数sortをTrueとします。

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

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

インデックス(行ラベル)をキーに指定する場合は、引数left_index, right_indexをTrueとします。 引数left_on, rihgt_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.DataFrameのjoin()メソッドを使って結合することもできます。 join()はmerge()のようにpandas.join()関数は用意されておらず、pandas.DataFrameのメソッドだけなので注意。 merge()と異なり左結合(how='left')がデフォルト。

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

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

呼び出し元の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

join()の引数onはどちらのpandas.DataFrameに対する指定なのかややこしいので、インデックスをキーとしない場合はmerge()を使ったほうが分かりやすいかもしれない。 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

シェア

関連カテゴリー

Python pandas

pandasで要素、行、列に関数を適用するmap, applymap, apply pandas.DataFrameに列や行を追加(assign, appendなど) pandasのcrosstabでクロス集計(カテゴリ毎の出現回数・頻度を算出) Python, pandas, seabornでヒートマップを作成 Python, pandasでwebページの表(htmlのtable)をスクレイピング pandas.DataFrame, Seriesのインデックスを振り直すreset_index pandas.DataFrameのforループ処理(イテレーション) pandasの時系列データのタイムゾーンを処理(tz_convert, tz_localize) Pythonで正規化・標準化(リスト、NumPy配列、pandas.DataFrame) pandas.DataFrame, Seriesを時系列データとして処理 pandas.DataFrame, Seriesの先頭・末尾の行を返すheadとtail pandas.DataFrameから条件を満たす行名・列名の行・列を抽出(選択) pandasで中央値を取得するmedian pandas.DataFrameの各列間の相関係数を算出、ヒートマップで可視化 『Pythonデータサイエンスハンドブック』は良書(NumPy, pandasほか)

Last Updated: 6/26/2019, 10:34:03 PM