Pandas Mesclando 101
- Como fazer um (
INNER
| (LEFT
|RIGHT
|FULL
)OUTER
)JOIN
com 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
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
merge
ejoin
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
NaN
s no resultado
Para realizar um INNER JOIN, chame merge
o 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 left
e right
que 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 left
serão usadas e os dados ausentes de serão right
substituí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 right
são usadas e os dados ausentes de left
sã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 left
apenas 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, left
tem keyLeft
, e right
tem em keyRight
vez de key
- então você terá que especificar left_on
e right_on
como 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 keyLeft
de left
e keyRight
de right
, se desejar apenas um keyLeft
ou 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 keyLeft
está 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_on
e 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
Mesclando um DataFrame com Series no índice : veja esta resposta .
Além disso
merge
,DataFrame.update
eDataFrame.combine_first
também são usados em certos casos para atualizar um DataFrame com outro.pd.merge_ordered
é uma função útil para JOINs ordenados.pd.merge_asof
(leia: merge_asOf) é útil para junções aproximadas .
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
, join
econcat
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_on
e right_on
conforme 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.join
quais padrões são joins no índice. DataFrame.join
faz 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 lsuffix
e, rsuffix
pois 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.concat
de @piRSquared .
Generalizando: merge
criando vários DataFrames
Muitas vezes, a situação surge quando vários DataFrames devem ser mesclados. Ingenuamente, isso pode ser feito encadeando merge
chamadas:
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.concat
junções de várias vias em chaves exclusivas e as DataFrame.join
junçõ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.concat
junta 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 join
descritas 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 join
uma vez que ele pode lidar com chaves não exclusivas (observe que join
junta DataFrames em seu índice; ele chama merge
sob 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
Uma visão visual suplementar de pd.concat([df0, df1], kwargs)
. Observe que o significado de kwarg axis=0
ou axis=1
não é tão intuitivo quanto df.mean()
oudf.apply(func)
Nesta resposta, considerarei um exemplo prático de pandas.concat
.
Considerando o seguinte DataFrames
com 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 )