Pandas fusionnant 101
- Comment effectuer un (
INNER
| (LEFT
|RIGHT
|FULL
)OUTER
)JOIN
avec des pandas? - Comment ajouter des NaN pour les lignes manquantes après la fusion?
- Comment puis-je me débarrasser des NaN après la fusion?
- Puis-je fusionner sur l'index?
- Rejoindre les pandas?
- Comment fusionner plusieurs DataFrames?
merge
?join
?concat
?update
? OMS? Quelle? Pourquoi?!
... et plus. J'ai vu ces questions récurrentes sur les différentes facettes de la fonctionnalité de fusion des pandas. La plupart des informations concernant la fusion et ses divers cas d'utilisation sont aujourd'hui fragmentées dans des dizaines de messages mal rédigés et insondables. Le but ici est de rassembler certains des points les plus importants pour la postérité.
Ce QnA est censé être le prochain épisode d'une série de guides d'utilisation utiles sur les idiomes courants des pandas (voir cet article sur le pivotement et cet article sur la concaténation , que je reviendrai plus tard).
Veuillez noter que cet article n'est pas destiné à remplacer la documentation , veuillez donc le lire également! Certains des exemples sont tirés de là.
Réponses
Cet article vise à donner aux lecteurs un aperçu de la fusion SQL avec les pandas, comment l'utiliser et quand ne pas l'utiliser.
En particulier, voici ce que cet article va parcourir:
Les bases - types de jointures (GAUCHE, DROITE, EXTÉRIEUR, INTÉRIEUR)
- fusion avec différents noms de colonnes
- éviter la colonne de clé de fusion en double dans la sortie
Fusion avec l'index dans différentes conditions
- en utilisant efficacement votre index nommé
- la clé de fusion comme l'index de l'un et la colonne de l'autre
Fusion multi-voies sur les colonnes et les index (uniques et non uniques)
Alternatives notables à
merge
etjoin
Ce que ce message ne passera pas:
- Discussions et horaires liés à la performance (pour l'instant). Mentions surtout notables de meilleures alternatives, le cas échéant.
- Gérer les suffixes, supprimer des colonnes supplémentaires, renommer les sorties et autres cas d'utilisation spécifiques. Il y a d'autres articles (lire: mieux) qui traitent de cela, alors découvrez-le!
Remarque
La plupart des exemples utilisent par défaut les opérations INNER JOIN lors de la démonstration de diverses fonctionnalités, sauf indication contraire.De plus, tous les DataFrames ici peuvent être copiés et répliqués afin que vous puissiez jouer avec eux. Consultez également cet article sur la façon de lire des DataFrames à partir de votre presse-papiers.
Enfin, toutes les représentations visuelles des opérations JOIN ont été dessinées à la main à l'aide de Google Drawings. Inspiration d' ici .
Assez parlé, montrez-moi simplement comment l'utiliser merge
!
Installer
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
Par souci de simplicité, la colonne clé porte le même nom (pour l'instant).
Un INNER JOIN est représenté par
Notez
ceci, ainsi que les chiffres à venir, tous suivent cette convention:
- le bleu indique les lignes présentes dans le résultat de la fusion
- le rouge indique les lignes exclues du résultat (c'est-à-dire supprimées)
- le vert indique les valeurs manquantes qui sont remplacées par
NaN
s dans le résultat
Pour effectuer une INNER JOIN, appelez merge
le DataFrame gauche, en spécifiant le DataFrame droit et la clé de jointure (au moins) comme arguments.
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
Cela ne renvoie que les lignes de left
et right
qui partagent une clé commune (dans cet exemple, "B" et "D).
Une jointure externe gauche ou une jointure gauche est représentée par
Cela peut être effectué en spécifiant 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
Notez soigneusement l'emplacement des NaN ici. Si vous spécifiez how='left'
, seules les clés de left
sont utilisées et les données manquantes de right
sont remplacées par NaN.
Et de même, pour une jointure externe droite ou une jointure droite qui est ...
... préciser 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
Ici, les clés de right
sont utilisées et les données manquantes de left
sont remplacées par NaN.
Enfin, pour la FULL OUTER JOIN , donnée par
préciser 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
Cela utilise les clés des deux cadres et des NaN sont insérés pour les lignes manquantes dans les deux.
La documentation résume bien ces différentes fusions:
Autres JOINs - GAUCHE-Excluant, DROITE-Excluant et FULL-Excluant / ANTI JOINs
Si vous avez besoin de JOINs d'exclusion GAUCHE et de JOIN d'exclusion DROITE en deux étapes.
Pour LEFT-Excluding JOIN, représenté par
Commencez par effectuer une JOINTURE EXTÉRIEURE GAUCHE puis filtrer (exclure!) Les lignes provenant left
uniquement,
(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
Où,
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
Et de même, pour un JOIN Excluant DROIT,
(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
Enfin, si vous devez effectuer une fusion qui ne conserve que les clés de gauche ou de droite, mais pas les deux (IOW, exécution d'un ANTI-JOIN ),
Vous pouvez le faire de la même manière:
(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
Différents noms pour les colonnes clés
Si les colonnes clés sont nommées différemment (par exemple, left
a keyLeft
et right
a keyRight
au lieu de key
), vous devrez alors spécifier left_on
et right_on
comme arguments au lieu 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
Éviter la colonne de clé en double dans la sortie
Lors de la fusion keyLeft
de left
et keyRight
de right
, si vous ne voulez que l'un des deux keyLeft
ou keyRight
(mais pas les deux) dans la sortie, vous pouvez commencer par définir l'index comme étape préliminaire.
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
Comparez cela avec la sortie de la commande juste avant (c'est-à-dire la sortie de left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')
), vous remarquerez qu'il keyLeft
manque. Vous pouvez déterminer la colonne à conserver en fonction de l'index de l'image défini comme clé. Cela peut avoir de l'importance, par exemple, lors de l'exécution d'une opération OUTER JOIN.
Fusionner une seule colonne de l'un des DataFrames
Par exemple, considérez
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
Si vous devez fusionner uniquement "new_val" (sans aucune des autres colonnes), vous pouvez généralement sous-définir les colonnes avant de fusionner:
left.merge(right3[['key', 'newcol']], on='key')
key value newcol
0 B 0.400157 0
1 D 2.240893 1
Si vous faites une jointure externe gauche, une solution plus performante impliquerait 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
Comme mentionné, c'est similaire à, mais plus rapide 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
Fusion sur plusieurs colonnes
Pour joindre sur plusieurs colonnes, spécifiez une liste pour on
(ou left_on
et right_on
, selon le cas).
left.merge(right, on=['key1', 'key2'] ...)
Ou, dans le cas où les noms sont différents,
left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])
Autres merge*
opérations et fonctions utiles
Fusion d'un DataFrame avec Series sur l'index : voir cette réponse .
En outre
merge
,DataFrame.update
etDataFrame.combine_first
sont également utilisés dans certains cas pour mettre à jour un DataFrame avec un autre.pd.merge_ordered
est une fonction utile pour les JOINs ordonnés.pd.merge_asof
(lire: merge_asOf) est utile pour les jointures approximatives .
Cette section ne couvre que les bases et est conçue pour vous aiguiser l'appétit. Pour plus d' exemples et de cas, consultez la documentation sur merge
, join
etconcat
ainsi que les liens vers les spécifications de la fonction.
Basé sur un index * -JOIN (+ colonnes d'index merge
)
Installer
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
En règle générale, une fusion sur l'index ressemblerait à ceci:
left.merge(right, left_index=True, right_index=True)
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Prise en charge des noms d'index
Si votre index est nommé, les utilisateurs de la version 0.23 peuvent également spécifier le nom du niveau à on
(ou left_on
et right_on
si nécessaire).
left.merge(right, on='idxkey')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Fusion sur index d'une, colonne (s) d'une autre
Il est possible (et assez simple) d'utiliser l'index d'un, et la colonne d'un autre, pour effectuer une fusion. Par exemple,
left.merge(right, left_on='key1', right_index=True)
Ou vice versa ( right_on=...
et 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
Dans ce cas particulier, l'index de left
est nommé, vous pouvez donc également utiliser le nom de l'index avec left_on
, comme ceci:
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
Outre ceux-ci, il existe une autre option succincte. Vous pouvez utiliser les DataFrame.join
valeurs par défaut pour les jointures sur l'index. DataFrame.join
fait une JOINTURE EXTÉRIEURE GAUCHE par défaut, c'est donc how='inner'
nécessaire ici.
left.join(right, how='inner', lsuffix='_x', rsuffix='_y')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Notez que j'avais besoin de spécifier les arguments lsuffix
et rsuffix
car join
sinon, l'erreur serait:
left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')
Puisque les noms de colonne sont les mêmes. Ce ne serait pas un problème s'ils étaient nommés différemment.
left.rename(columns={'value':'leftvalue'}).join(right, how='inner')
leftvalue value
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
pd.concat
Enfin, comme alternative aux jointures basées sur des index, vous pouvez utiliser 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
Omettez join='inner'
si vous avez besoin d'une FULL OUTER JOIN (par défaut):
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
Pour plus d'informations, consultez cet article canonique sur pd.concat
par @piRSquared .
Généralisation: merge
ingérer plusieurs DataFrames
Souvent, la situation se produit lorsque plusieurs DataFrames doivent être fusionnés. Naïvement, cela peut être fait en chaînant les merge
appels:
df1.merge(df2, ...).merge(df3, ...)
Cependant, cela devient rapidement incontrôlable pour de nombreux DataFrames. De plus, il peut être nécessaire de généraliser pour un nombre inconnu de DataFrames.
Je présente ici pd.concat
pour les jointures multi-voies sur des clés uniques et DataFrame.join
pour les jointures multi-voies sur des clés non uniques . Tout d'abord, la configuration.
# 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]
Fusion multi-voies sur des clés uniques (ou index)
Si vos clés (ici, la clé peut être une colonne ou un index) sont uniques, vous pouvez utiliser pd.concat
. Notez que pd.concat
joint DataFrames sur l'index .
# 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
Omettre join='inner'
pour une jointure externe complète. Notez que vous ne pouvez pas spécifier de jointures EXTÉRIEURES GAUCHE ou DROITE (si vous en avez besoin, utilisez join
, décrit ci-dessous).
Fusion multi-voies sur les clés avec des doublons
concat
est rapide, mais a ses défauts. Il ne peut pas gérer les doublons.
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)
Dans cette situation, nous pouvons l'utiliser join
car il peut gérer des clés non uniques (notez que join
joint les DataFrames sur leur index; il appelle merge
sous le capot et fait un LEFT OUTER JOIN sauf indication contraire).
# 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
Une vue visuelle supplémentaire de pd.concat([df0, df1], kwargs)
. Notez que la signification de kwarg axis=0
ou axis=1
n'est pas aussi intuitive que df.mean()
oudf.apply(func)
Dans cette réponse, je considérerai un exemple pratique du pandas.concat
.
Considérant ce qui suit DataFrames
avec les mêmes noms de colonne:
Preco2018 avec taille (8784, 5)
Preco 2019 avec taille (8760, 5)
Qui ont les mêmes noms de colonnes.
Vous pouvez les combiner en utilisant pandas.concat
, simplement
import pandas as pd
frames = [Preco2018, Preco2019]
df_merged = pd.concat(frames)
Ce qui donne un DataFrame avec la taille suivante (17544, 5)
Si vous voulez visualiser, cela finit par fonctionner comme ça
( Source )