note.nkmk.me

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

Date: 2018-08-04 / tags: Python, pandas
このエントリーをはてなブックマークに追加

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

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

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

  • 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

引数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用サフィックス]というリストやタプルを指定する。

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

キー列でソートする場合は引数sortTrueとする。

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_indexTrueとする。

引数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()メソッドを使ってもOK。

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

インデックスをキーにする場合はpandas.DataFramejoin()メソッドを使って結合することもできる。

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
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事