web-dev-qa-db-ja.com

パンダマジック101

  • LEFT | RIGHT | FULL)(INNER | OUTER)をパンダと結合する方法
  • マージ後に不足している行にNaNを追加する方法
  • マージ後にどのようにしてNaNを削除できますか?
  • インデックスにマージできますか?
  • パンダとクロスジョインしますか?
  • 複数のDataFrameをマージする方法
  • mergejoinconcatupdate?誰?何?なぜ?!

... もっと。私はこれらの繰り返しの質問がパンダマージ機能の様々な面について尋ねるのを見ました。今日のマージとそのさまざまなユースケースに関する情報の大部分は、何十ものひどく、検索できない投稿にまたがって断片化されています。ここでの目的は、後世のためのいくつかのより重要な点を照合することです。

このQnAは、一般的なパンダの慣用句に関する一連の有用なユーザーガイドの次の記事です( ピボット に関するこの記事と 連結に関するこの記事を参照)。 、後で触れます)。

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

187
cs95

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

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

  • 基本-結合の種類(左、右、外側、内側)

    • 異なる列名とのマージ
    • 出力でのマージキー列の重複を避ける
  • さまざまな条件下でのインデックスとのマージ
    • 名前付きインデックスを効果的に使用する
    • キーをあるインデックスと別のカラムのインデックスとしてマージする
  • 列とインデックスの多方向マージ(一意および非一意)
  • mergeおよびjoinの注目すべき代替品

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

  • パフォーマンス関連の議論とタイミング(今のところ)。適切な場合には、より優れた代替案の主な言及。
  • サフィックスの処理、余分な列の削除、出力の名前変更、およびその他の特定のユースケース。それに対処する他の(読む:より良い)投稿がありますので、理解してください!


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

さらに、ここですべてのDataFramesをコピーして複製できるため、それらを操作できます。また、クリップボードからDataFrameを読み取る方法については この投稿 を参照してください。

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

十分な話、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は、


これは、今後の数字とともに、すべてこの規則に従います。

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

INNER JOINを実行するには、 pd.merge を呼び出して、左側のDataFrame、右側のDataFrame、および結合キーを指定します。

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

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

これは、共通キー(この例では「B」と「D」)を共有するleftrightからの行のみを返します。

pandas(v0.21程度)の最近のバージョンでは、mergeが1次関数になったため、 DataFrame.merge を呼び出すことができます。

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

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が挿入されます。

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

enter image description here

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

必要な場合LEFT-Exclude JOINsおよびRIGHT-Exclude JOINsステップ。

LEFT-Exclude 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

同様に、右を除くJOINの場合、

(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

キー列の異なる名前

キー列の名前が異なる場合(たとえば、leftkeyLeftがあり、rightkeyRightの代わりにkeyがある場合は、left_onを指定する必要があります。 onの代わりに引数としてright_on

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

出力での重複キー列の回避

keyLeftからleftkeyRightからrightからkeyLeftをマージする場合、keyRightまたはkeyLeftのいずれか(両方ではない)のみが必要な場合出力では、予備ステップとしてインデックスを設定することから開始できます。

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')の出力)と比較すると、DataFramesが欠落していることがわかります。どのフレームのインデックスがキーとして設定されているかに基づいて、保持する列を把握できます。これは、たとえば、OUTER JOIN操作を実行するときに重要になる場合があります。

[VARIABLE]の1つから単一の列のみをマージする

たとえば、考慮してください

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)のリストを指定します。

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

または、イベントが異なる場合、

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

その他の便利なmerge*操作と関数

  • インデックス上のシリーズとのDataFrameのマージthis answer を参照してください。
  • mergeに加えて、 DataFrame.update および DataFrame.combine_first は、特定の場合に、あるDataFrameを別のDataFrameで更新するためにも使用されます。

  • pd.merge_ordered は、順序付けされたJOINに便利な関数です。

  • pd.merge_asof (読み取り:merge_asOf)は、approoximate結合に役立ちます。

このセクションでは、ごく基本的なことのみを取り上げ、あなたの食欲を刺激することのみを目的としています。その他の例とケースについては、 mergejoin、およびconcatのドキュメント および関数仕様へのリンクを参照してください。


インデックスベースの* -JOIN(+インデックス列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_onright_on)にレベル名を指定することもできます。

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

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

一方のインデックス、別のカラムのマージ

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

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

lsuffixはエラーになるので、rsuffix引数と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

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

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

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


一般化:mergeing複数のDataFrames

多くの場合、複数のDataFrameをマージするときに状況が発生します。単純に、これはmerge呼び出しを連鎖することで実行できます。

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

ただし、これは多くのDataFrameですぐに手に負えなくなります。さらに、不明な数のDataFrameに対して一般化する必要がある場合があります。

ここでは、uniqueキーでの多方向結合のpd.concatと、non-uniqueキーでの多方向結合の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.concatを使用できます。 pd.concatは、インデックス上のデータフレームを結合することに注意してください

# 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

FULL OUTER JOINの場合はjoin='inner'を省略します。 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はインデックスのDataFramesに参加します。フードの下で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
299
cs95

pd.concat([df0, df1], kwargs)の補足的なビジュアルビュー。 axis=0axis=1df.mean()df.apply(foo)のように直感的ではないために作りました。

on pd.concat([df0, df1])

12
eliu