パンダのマージ101


365
  • パンダと(LEFT| RIGHT| FULL)(INNER| OUTER)結合を実行する方法?
  • マージ後に不足している行にNaNを追加するにはどうすればよいですか?
  • マージ後にNaNを取り除くにはどうすればよいですか?
  • インデックスでマージできますか?
  • パンダと一緒に参加しますか?
  • 複数のデータフレームをマージするにはどうすればよいですか?
  • mergejoinconcatupdate?WHO?何?なぜ?!

... もっと。私はパンダのマージ機能のさまざまな側面について尋ねるこれらの繰り返しの質問を見てきました。今日のマージとそのさまざまな使用例に関するほとんどの情報は、不適切な言葉で検索できない数十の投稿に断片化されています。ここでの目的は、後世のためのいくつかのより重要なポイントを照合することです。

このQnAは、一般的なパンダのイディオムに関する一連の役立つユーザーガイドの次の記事になることを意図しています(ピボットに関するこの投稿と、後で説明する連結に関するこの投稿を参照してください)。

この投稿はドキュメントの代わりとなるものではないので注意してください。いくつかの例はそこから取られています。

回答:


520

この投稿は、パンダとのSQL風味のマージ、その使用方法、および使用しない場合の入門書を読者に提供することを目的としています。

特に、この投稿の内容は次のとおりです。

  • 基本-結合のタイプ(LEFT、RIGHT、OUTER、INNER)

    • 異なる列名とのマージ
    • 出力で重複するマージキー列を回避する
  • さまざまな条件下でのインデックスとのマージ
    • 名前付きインデックスを効果的に使用する
    • 1つのインデックスと別の列としてキーをマージする
  • 列とインデックスのマルチウェイマージ(一意および非一意)
  • mergeおよびの注目すべき代替案join

この投稿が通過しないこと:

  • パフォーマンス関連のディスカッションとタイミング(現時点では)。適切な場合は常に、より優れた代替案についての最も注目すべき言及。
  • サフィックスの処理、余分な列の削除、出力の名前変更、およびその他の特定の使用例。これに対処する他の(読む:より良い)投稿があるので、それを理解してください!


特に指定のない限り、ほとんどの例では、さまざまな機能を示しながら、デフォルトでINNER JOIN操作が行われます。

さらに、ここにあるすべてのデータフレームをコピーして複製できるため、それらを使って遊ぶことができます。また、 クリップボードからDataFrameを読み取る方法については、この投稿を参照してください。

最後に、JOIN操作のすべての視覚的表現は、Google図形描画を使用して手書きされています。ここからのインスピレーション。

十分な話、使い方を教えてくださいmerge

セットアップ

np.random.seed(0)
left = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value': np.random.randn(4)})    
right = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value': np.random.randn(4)})

left

  key     value
0   A  1.764052
1   B  0.400157
2   C  0.978738
3   D  2.240893

right

  key     value
0   B  1.867558
1   D -0.977278
2   E  0.950088
3   F -0.151357

簡単にするために、キーカラムは同じ名前です(今のところ)。

アンINNER JOINはで表され、

なお、
今後の数値はすべて、この規則に従うとともに、これを:

  • は、マージ結果に存在する行を示します
  • は、結果から除外された(つまり、削除された)行を示します
  • は、結果でNaNに置き換えられる欠損値を示します

INNER JOINを実行するmergeには、左側のDataFrameを呼び出し、右側のDataFrameと結合キー(少なくとも)を引数として指定します。

left.merge(right, on='key')
# Or, if you want to be explicit
# left.merge(right, on='key', how='inner')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278

この戻り行のみからleftright共有する共通鍵(この例では、「B」および「D)。

A LEFT OUTER JOIN、またはLEFT JOINは、がで表され

これは、を指定することで実行できますhow='left'

left.merge(right, on='key', how='left')

  key   value_x   value_y
0   A  1.764052       NaN
1   B  0.400157  1.867558
2   C  0.978738       NaN
3   D  2.240893 -0.977278

ここでNaNの配置に注意してください。を指定するとhow='left'、からのキーのみleftが使用され、からの欠落データrightはNaNに置き換えられます。

同様に、RIGHT OUTER JOINまたはRIGHT JOINの場合...

...具体的にhow='right'

left.merge(right, on='key', how='right')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278
2   E       NaN  0.950088
3   F       NaN -0.151357

ここでは、からのキーrightが使用され、からの欠落データleftはNaNに置き換えられます。

最後に、以下によって与えられるFULL OUTER JOINについて、

を指定しますhow='outer'

left.merge(right, on='key', how='outer')

  key   value_x   value_y
0   A  1.764052       NaN
1   B  0.400157  1.867558
2   C  0.978738       NaN
3   D  2.240893 -0.977278
4   E       NaN  0.950088
5   F       NaN -0.151357

これは両方のフレームのキーを使用し、NaNは両方の欠落行に挿入されます。

ドキュメントはこれらの様々なマージをうまくまとめています:

ここに画像の説明を入力してください

その他の結合-左除外、右除外、および完全除外/ ANTI結合

2つの手順でLEFT除外JOINRIGHT 除外JOINが必要な場合。

左除外結合の場合、次のように表されます

LEFT OUTER JOINを実行してからleft、次の行のみをフィルタリング(除外!)します。

(left.merge(right, on='key', how='left', indicator=True)
     .query('_merge == "left_only"')
     .drop('_merge', 1))

  key   value_x  value_y
0   A  1.764052      NaN
2   C  0.978738      NaN

どこ、

left.merge(right, on='key', how='left', indicator=True)

  key   value_x   value_y     _merge
0   A  1.764052       NaN  left_only
1   B  0.400157  1.867558       both
2   C  0.978738       NaN  left_only
3   D  2.240893 -0.977278       both

同様に、右除外結合の場合、

(left.merge(right, on='key', how='right', indicator=True)
     .query('_merge == "right_only"')
     .drop('_merge', 1))

  key  value_x   value_y
2   E      NaN  0.950088
3   F      NaN -0.151357

最後に、左または右からのキーのみを保持し、両方は保持しないマージを実行する必要がある場合(IOW、ANTI-JOINの実行)、

同様の方法でこれを行うことができます—

(left.merge(right, on='key', how='outer', indicator=True)
     .query('_merge != "both"')
     .drop('_merge', 1))

  key   value_x   value_y
0   A  1.764052       NaN
2   C  0.978738       NaN
4   E       NaN  0.950088
5   F       NaN -0.151357

キー列の異なる名前

キー列の名前が異なる場合(たとえば、lefthas keyLeftrighthasのkeyRight代わりに)は、次の代わりにおよびを引数としてkey指定する必要がleft_onあります。right_onon

left2 = left.rename({'key':'keyLeft'}, axis=1)
right2 = right.rename({'key':'keyRight'}, axis=1)

left2

  keyLeft     value
0       A  1.764052
1       B  0.400157
2       C  0.978738
3       D  2.240893

right2

  keyRight     value
0        B  1.867558
1        D -0.977278
2        E  0.950088
3        F -0.151357

left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')

  keyLeft   value_x keyRight   value_y
0       B  0.400157        B  1.867558
1       D  2.240893        D -0.977278

出力でのキー列の重複を回避する

keyLeftfrom leftkeyRightfromをマージするときに、出力にまたはのrightいずれかのみ(両方ではない)が必要な場合は、最初のステップとしてインデックスを設定することから始めます。keyLeftkeyRight

left3 = left2.set_index('keyLeft')
left3.merge(right2, left_index=True, right_on='keyRight')

    value_x keyRight   value_y
0  0.400157        B  1.867558
1  2.240893        D -0.977278

これを直前のコマンドの出力(つまり、の出力left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner'))と比較すると、欠落していることがわかりますkeyLeft。どのフレームのインデックスがキーとして設定されているかに基づいて、保持する列を特定できます。これは、たとえば、いくつかのOUTER JOIN操作を実行するときに問題になる場合があります。

のいずれかから単一の列のみをマージする DataFrames

たとえば、

right3 = right.assign(newcol=np.arange(len(right)))
right3
  key     value  newcol
0   B  1.867558       0
1   D -0.977278       1
2   E  0.950088       2
3   F -0.151357       3

「new_val」のみをマージする必要がある場合(他の列はなし)、通常はマージする前に列をサブセット化できます。

left.merge(right3[['key', 'newcol']], on='key')

  key     value  newcol
0   B  0.400157       0
1   D  2.240893       1

LEFT OUTER JOINを実行している場合、よりパフォーマンスの高いソリューションには以下が含まれmapます。

# left['newcol'] = left['key'].map(right3.set_index('key')['newcol']))
left.assign(newcol=left['key'].map(right3.set_index('key')['newcol']))

  key     value  newcol
0   A  1.764052     NaN
1   B  0.400157     0.0
2   C  0.978738     NaN
3   D  2.240893     1.0

前述のように、これは似ていますが、

left.merge(right3[['key', 'newcol']], on='key', how='left')

  key     value  newcol
0   A  1.764052     NaN
1   B  0.400157     0.0
2   C  0.978738     NaN
3   D  2.240893     1.0

複数の列でのマージ

複数の列を結合するには、リストon(またはleft_onright_on必要に応じてand )を指定します。

left.merge(right, on=['key1', 'key2'] ...)

または、名前が異なる場合は、

left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])

その他の便利なmerge*操作と機能

このセクションでは、ごく基本的な内容のみを取り上げ、食欲を刺激することのみを目的としています。より多くの例と例については、参照のドキュメントをmergejoinconcatだけでなく、機能仕様へのリンク。


インデックスベースの* -JOIN(+ index-column merges)

セットアップ

np.random.seed([3, 14])
left = pd.DataFrame({'value': np.random.randn(4)}, index=['A', 'B', 'C', 'D'])    
right = pd.DataFrame({'value': np.random.randn(4)}, index=['B', 'D', 'E', 'F'])
left.index.name = right.index.name = 'idxkey'

left
           value
idxkey          
A      -0.602923
B      -0.402655
C       0.302329
D      -0.524349

right

           value
idxkey          
B       0.543843
D       0.013135
E      -0.326498
F       1.385076

通常、インデックスのマージは次のようになります。

left.merge(right, left_index=True, right_index=True)


         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

インデックス名のサポート

あなたのインデックスが命名されている場合は、v0.23ユーザーもにレベル名を指定することができますon(またはleft_onおよびright_on必要に応じて)。

left.merge(right, on='idxkey')

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

1つのインデックス、別の列のマージ

マージを実行するために、1つのインデックスと別のインデックスを使用することができます(非常に簡単です)。例えば、

left.merge(right, left_on='key1', right_index=True)

またはその逆(right_on=...およびleft_index=True)。

right2 = right.reset_index().rename({'idxkey' : 'colkey'}, axis=1)
right2

  colkey     value
0      B  0.543843
1      D  0.013135
2      E -0.326498
3      F  1.385076

left.merge(right2, left_index=True, right_on='colkey')

    value_x colkey   value_y
0 -0.402655      B  0.543843
1 -0.524349      D  0.013135

この特別なケースでは、のインデックスにleft名前が付けられているためleft_on、次のようにでインデックス名を使用できます。

left.merge(right2, left_on='idxkey', right_on='colkey')

    value_x colkey   value_y
0 -0.402655      B  0.543843
1 -0.524349      D  0.013135

DataFrame.join
これらに加えて、別の簡潔なオプションがあります。DataFrame.joinインデックスで結合するデフォルトを使用できます。DataFrame.joinデフォルトではLEFT OUTER JOINを実行するため、ここhow='inner'で必要です。

left.join(right, how='inner', lsuffix='_x', rsuffix='_y')

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

lsuffixrsuffix引数を指定する必要があることに注意してください。joinそうしないとエラーになります。

left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')

列名は同じなので。名前が異なる場合、これは問題にはなりません。

left.rename(columns={'value':'leftvalue'}).join(right, how='inner')

        leftvalue     value
idxkey                     
B       -0.402655  0.543843
D       -0.524349  0.013135

pd.concat
最後に、インデックスベースの結合の代替として、次を使用できますpd.concat

pd.concat([left, right], axis=1, sort=False, join='inner')

           value     value
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

join='inner'FULL OUTER JOIN(デフォルト)が必要な場合は省略します。

pd.concat([left, right], axis=1, sort=False)

      value     value
A -0.602923       NaN
B -0.402655  0.543843
C  0.302329       NaN
D -0.524349  0.013135
E       NaN -0.326498
F       NaN  1.385076

詳細についてpd.concat、@ piRSquaredによるこの正規の投稿を参照てください


一般化:merge複数のデータフレームを使用する

多くの場合、状況は複数のデータフレームが一緒にマージされるときに発生します。簡単に言えば、これはmerge呼び出しを連鎖させることによって行うことができます:

df1.merge(df2, ...).merge(df3, ...)

ただし、これは多くのデータフレームではすぐに手に負えなくなります。さらに、不明な数のデータフレームを一般化する必要がある場合があります。

ここで私は紹介pd.concatマルチウェイは、上の加入のためのユニークなキー、およびDataFrame.joinマルチウェイのために参加する非ユニークキー。まず、セットアップ。

# Setup.
np.random.seed(0)
A = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'valueA': np.random.randn(4)})    
B = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'valueB': np.random.randn(4)})
C = pd.DataFrame({'key': ['D', 'E', 'J', 'C'], 'valueC': np.ones(4)})
dfs = [A, B, C] 

# Note, the "key" column values are unique, so the index is unique.
A2 = A.set_index('key')
B2 = B.set_index('key')
C2 = C.set_index('key')

dfs2 = [A2, B2, C2]

一意のキー(またはインデックス)での多方向マージ

キー(ここでは、キーは列またはインデックスのいずれか)が一意である場合は、を使用できますpd.concatpd.concatは、インデックスでDataFrame結合します

# merge on `key` column, you'll need to set the index before concatenating
pd.concat([
    df.set_index('key') for df in dfs], axis=1, join='inner'
).reset_index()

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

# merge on `key` index
pd.concat(dfs2, axis=1, sort=False, join='inner')

       valueA    valueB  valueC
key                            
D    2.240893 -0.977278     1.0

join='inner'FULL OUTER JOINは省略します。LEFTまたはRIGHT OUTER結合は指定できないことに注意してください(これらが必要な場合はjoin、以下で説明するを使用してください)。

重複のあるキーの多方向マージ

concat高速ですが、欠点があります。重複は処理できません。

A3 = pd.DataFrame({'key': ['A', 'B', 'C', 'D', 'D'], 'valueA': np.random.randn(5)})

pd.concat([df.set_index('key') for df in [A3, B, C]], axis=1, join='inner')
ValueError: Shape of passed values is (3, 4), indices imply (3, 2)

この状況では、join一意ではないキーを処理できるため、これを使用できます(joinインデックスでDataFrame を結合します。merge特に指定のない限り、内部で呼び出し、LEFT OUTER JOINを実行します)。

# join on `key` column, set as the index first
# For inner join. For left join, omit the "how" argument.
A.set_index('key').join(
    [df.set_index('key') for df in (B, C)], how='inner').reset_index()

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

# join on `key` index
A3.set_index('key').join([B2, C2], how='inner')

       valueA    valueB  valueC
key                            
D    1.454274 -0.977278     1.0
D    0.761038 -0.977278     1.0

49

の補足的な視覚的ビューpd.concat([df0, df1], kwargs)。kwarg axis=0またはaxis=1の意味は、df.mean()またはほど直感的ではないことに注意してください。df.apply(func)


pd.concat([df0、df1])


9
これは素晴らしい図です。どのように作成したのですか。
cs95

6
google docの組み込みの「挿入==>描画... ==>新規」(2019年5月現在)。ただし、明確にするために、この画像にgoogle docを使用した唯一の理由は、メモがgoogle docに保存されているためです。また、google doc内ですばやく変更できる画像が必要です。実際、あなたはそれについて言及しましたが、Googleドキュメントの描画ツールはかなりすっきりしています。
eliu

わあ、これは素晴らしいです。SQLの世界から来ると、「垂直」結合は頭の中での結合ではありません。テーブルの構造は常に固定されているからです。今でもパンダは統合すべきだと思うconcatし、merge方向パラメータがあることをhorizontalvertical
Ufos

2
@Ufosそれはまさに何でaxis=1あり、そうではありませんaxis=0か?
cs95

2
はい、ありmergeconcatそして軸と何でもあります。ただし、@ eliuが示すように、「左」と「右」および「水平」または「垂直」とマージするという概念はすべて同じです。私は、個人的には、ドキュメントの中に私がしている「軸」を覚えておく必要があり毎回見ている0とされているが1
Ufos
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.