Pandas Mesclando 101

Dec 06 2018
  • Como fazer um ( INNER| ( LEFT| RIGHT| FULL) OUTER) JOINcom pandas?
  • Como adiciono NaNs para linhas ausentes após a mesclagem?
  • Como me livro dos NaNs após a fusão?
  • Posso mesclar no índice?
  • Cross join com pandas?
  • Como faço para mesclar vários DataFrames?
  • merge? join? concat? update? Who? O que? Por quê?!

... e mais. Já vi essas perguntas recorrentes sobre as várias facetas da funcionalidade de mesclagem do pandas. A maior parte das informações sobre mesclagem e seus vários casos de uso hoje está fragmentada em dezenas de postagens mal formuladas e insondáveis. O objetivo aqui é reunir alguns dos pontos mais importantes para a posteridade.

Este QnA pretende ser o próximo capítulo de uma série de guias de usuário úteis sobre expressões idiomáticas comuns de pandas (veja este post sobre pivotamento e este post sobre concatenação , que irei abordar mais tarde).

Observe que esta postagem não tem o objetivo de substituir a documentação , portanto, leia também! Alguns dos exemplos foram tirados daí.

Respostas

696 cs95 Dec 06 2018 at 13:41

Este post tem como objetivo dar aos leitores uma introdução sobre a fusão com o sabor SQL com pandas, como usá-lo e quando não usá-lo.

Em particular, aqui está o que esta postagem vai passar:

  • O básico - tipos de junções (LEFT, RIGHT, OUTER, INNER)

    • mesclando com nomes de coluna diferentes
    • evitando duplicar a coluna chave de mesclagem na saída
  • Mesclando com o índice em condições diferentes

    • efetivamente usando seu índice nomeado
    • chave de mesclagem como o índice de um e coluna de outro
  • Multiway mescla em colunas e índices (exclusivos e não exclusivos)

  • Alternativas notáveis ​​para mergeejoin

O que esta postagem não passará:

  • Discussões e horários relacionados ao desempenho (por enquanto). Principalmente menções notáveis ​​de melhores alternativas, sempre que apropriado.
  • Manipular sufixos, remover colunas extras, renomear saídas e outros casos de uso específicos. Existem outros (leia-se: melhores) posts que tratam disso, então descubra!

Observação
A maioria dos exemplos usa como padrão as operações INNER JOIN ao demonstrar vários recursos, a menos que especificado de outra forma.

Além disso, todos os DataFrames aqui podem ser copiados e replicados para que você possa brincar com eles. Além disso, veja esta postagem sobre como ler DataFrames de sua área de transferência.

Por último, todas as representações visuais das operações JOIN foram desenhadas à mão usando o Desenhos Google. Inspiração daqui .

Chega de conversa, apenas me mostre como usar merge!

Configuração

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

Para simplificar, a coluna-chave tem o mesmo nome (por enquanto).

Um INNER JOIN é representado por

Observe que
, juntamente com os próximos números, todos seguem esta convenção:

  • azul indica as linhas que estão presentes no resultado da mesclagem
  • vermelho indica linhas que são excluídas do resultado (ou seja, removidas)
  • verde indica valores ausentes que são substituídos por NaNs no resultado

Para realizar um INNER JOIN, chame mergeo DataFrame esquerdo, especificando o DataFrame direito e a chave de junção (no mínimo) como argumentos.

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

Isso retorna apenas as linhas de lefte rightque compartilham uma chave comum (neste exemplo, "B" e "D).

A LEFT OUTER JOIN ou LEFT JOIN é representada por

Isso pode ser executado especificando 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

Observe cuidadosamente a colocação dos NaNs aqui. Se você especificar how='left', apenas as chaves de leftserão usadas e os dados ausentes de serão rightsubstituídos por NaN.

E da mesma forma, para um RIGHT OUTER JOIN ou RIGHT JOIN que é ...

... especifique 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

Aqui, as chaves de rightsão usadas e os dados ausentes de leftsão substituídos por NaN.

Finalmente, para o FULL OUTER JOIN , fornecido por

especificar 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

Isso usa as chaves de ambos os quadros, e NaNs são inseridos para linhas ausentes em ambos.

A documentação resume muito bem essas várias fusões:

Outros JOINs - Excluindo LEFT, Excluindo RIGHT e Excluindo FULL / ANTI JOINs

Se você precisar de LEFT-Excluindo JOINs e RIGHT-Excluindo JOINs em duas etapas.

Para LEFT-Excluindo JOIN, representado como

Comece executando LEFT OUTER JOIN e, em seguida, filtrando (excluindo!) As linhas provenientes leftapenas de,

(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

Onde,

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

E da mesma forma, para um JOIN de exclusão de DIREITO,

(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

Por último, se você for obrigado a fazer uma mesclagem que retenha apenas as chaves da esquerda ou direita, mas não de ambas (IOW, executando um ANTI-JOIN ),

Você pode fazer isso de maneira semelhante -

(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

Nomes diferentes para colunas-chave

Se as colunas-chave forem nomeadas de maneira diferente - por exemplo, lefttem keyLeft, e righttem em keyRightvez de key- então você terá que especificar left_one right_oncomo argumentos em vez de 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

Evitando coluna-chave duplicada na saída

Ao mesclar keyLeftde lefte keyRightde right, se desejar apenas um keyLeftou keyRight(mas não ambos) na saída, você pode começar definindo o índice como uma etapa preliminar.

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

Compare isso com a saída do comando imediatamente anterior (ou seja, a saída de left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')), você perceberá que keyLeftestá faltando. Você pode descobrir qual coluna manter com base em qual índice do quadro está definido como a chave. Isso pode ser importante quando, digamos, executar alguma operação OUTER JOIN.

Mesclando apenas uma única coluna de um dos DataFrames

Por exemplo, considere

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

Se você for obrigado a mesclar apenas "new_val" (sem qualquer uma das outras colunas), você geralmente pode apenas subconjunto de colunas antes de mesclar:

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

  key     value  newcol
0   B  0.400157       0
1   D  2.240893       1

Se você estiver fazendo um LEFT OUTER JOIN, uma solução de maior desempenho envolveria 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

Como mencionado, isso é semelhante, mas mais rápido do que

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

Mesclando em várias colunas

Para unir em mais de uma coluna, especifique uma lista para on(ou left_one right_on, conforme apropriado).

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

Ou, caso os nomes sejam diferentes,

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

Outras merge*operações e funções úteis

Esta seção cobre apenas o básico e foi criada para aguçar seu apetite. Para mais exemplos e casos, consulte a documentação sobre merge, joineconcat assim como os links para as especificações de função.


Baseado em índice * -JOIN (+ índice-colunas merge)

Configuração

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

Normalmente, uma mesclagem no índice ficaria assim:

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


         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Suporte para nomes de índice

Se o seu índice for nomeado, os usuários da v0.23 também podem especificar o nome do nível para on(ou left_one right_onconforme necessário).

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

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Mesclando no índice de um, coluna (s) de outro

É possível (e bastante simples) usar o índice de um e a coluna de outro para realizar uma fusão. Por exemplo,

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

Ou vice-versa ( right_on=...e 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

Neste caso especial, o índice para lefté nomeado, então você também pode usar o nome do índice com left_on, assim:

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
Além dessas, existe outra opção sucinta. Você pode usar DataFrame.joinquais padrões são joins no índice. DataFrame.joinfaz um LEFT OUTER JOIN por padrão, então how='inner'é necessário aqui.

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

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Observe que precisei especificar os argumentos lsuffixe, rsuffixpois join, de outra forma, haveria um erro:

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

Já que os nomes das colunas são os mesmos. Isso não seria um problema se eles tivessem nomes diferentes.

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

        leftvalue     value
idxkey                     
B       -0.402655  0.543843
D       -0.524349  0.013135

pd.concat
Por último, como alternativa para junções baseadas em índice, você pode usar 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

Omita join='inner'se você precisar de FULL OUTER JOIN (o padrão):

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

Para obter mais informações, consulte esta postagem canônica pd.concatde @piRSquared .


Generalizando: mergecriando vários DataFrames

Muitas vezes, a situação surge quando vários DataFrames devem ser mesclados. Ingenuamente, isso pode ser feito encadeando mergechamadas:

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

No entanto, isso rapidamente sai do controle para muitos DataFrames. Além disso, pode ser necessário generalizar para um número desconhecido de DataFrames.

Aqui, apresento as pd.concatjunções de várias vias em chaves exclusivas e as DataFrame.joinjunções de várias vias em chaves não exclusivas . Primeiro, a configuração.

# 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]

Mesclagem multiponto em chaves exclusivas (ou índice)

Se suas chaves (aqui, a chave pode ser uma coluna ou um índice) forem exclusivas, você pode usar pd.concat. Observe que pd.concatjunta DataFrames no índice .

# 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

Omitir join='inner'para um FULL OUTER JOIN. Observe que você não pode especificar as junções LEFT ou RIGHT OUTER (se precisar delas, use as joindescritas abaixo).

Multiway merge em chaves com duplicatas

concaté rápido, mas tem suas deficiências. Ele não pode lidar com duplicatas.

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)

Nesta situação, podemos usar joinuma vez que ele pode lidar com chaves não exclusivas (observe que joinjunta DataFrames em seu índice; ele chama mergesob o capô e faz um LEFT OUTER JOIN, a menos que especificado de outra forma).

# 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
62 eliu Apr 26 2019 at 06:43

Uma visão visual suplementar de pd.concat([df0, df1], kwargs). Observe que o significado de kwarg axis=0ou axis=1não é tão intuitivo quanto df.mean()oudf.apply(func)


5 GonçaloPeres龚燿禄 Aug 10 2020 at 17:13

Nesta resposta, considerarei um exemplo prático de pandas.concat.

Considerando o seguinte DataFramescom os mesmos nomes de coluna:

Preco2018 com tamanho (8784, 5)

Preco 2019 com tamanho (8760, 5)

Que têm os mesmos nomes de coluna.

Você pode combiná-los usando pandas.concat, simplesmente

import pandas as pd

frames = [Preco2018, Preco2019]

df_merged = pd.concat(frames)

O que resulta em um DataFrame com o seguinte tamanho (17544, 5)

Se você quiser visualizar acaba funcionando assim

( Fonte )