Quelle est la différence entre rejoindre et fusionner dans Pandas?

208

Supposons que j'ai deux DataFrames comme ceci:

left = pd.DataFrame({'key1': ['foo', 'bar'], 'lval': [1, 2]})

right = pd.DataFrame({'key2': ['foo', 'bar'], 'rval': [4, 5]})

Je veux les fusionner, alors j'essaye quelque chose comme ceci:

pd.merge(left, right, left_on='key1', right_on='key2')

Et je suis content

    key1    lval    key2    rval
0   foo     1       foo     4
1   bar     2       bar     5

Mais j'essaie d'utiliser la méthode de jointure, qui m'a amené à croire qu'elle est assez similaire.

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

Et je reçois ceci:

//anaconda/lib/python2.7/site-packages/pandas/tools/merge.pyc in _validate_specification(self)
    406             if self.right_index:
    407                 if not ((len(self.left_on) == self.right.index.nlevels)):
--> 408                     raise AssertionError()
    409                 self.right_on = [None] * n
    410         elif self.right_on is not None:

AssertionError: 

Qu'est-ce que je rate?

munk
la source
4
Le problème spécifique ici est qu'il mergejoint les colonnes de leftaux colonnes de right, ce qui est ce que vous voulez, mais join(... on=[...])joint les colonnes de leftpour indexer les clés de right, ce qui n'est pas ce que vous voulez. Voir ma réponse ci-dessous pour plus de détails.
Matthias Fripp
3
DataFrame.join () veut toujours faire correspondre les index ou clés de l'appelant (spécifiés par onoption) avec les otherindex de. N'oubliez pas, les index de jointure. Alors que merge () est une méthode plus générique.
Jiapeng Zhang

Réponses:

87

J'utilise toujours joinsur les indices:

import pandas as pd
left = pd.DataFrame({'key': ['foo', 'bar'], 'val': [1, 2]}).set_index('key')
right = pd.DataFrame({'key': ['foo', 'bar'], 'val': [4, 5]}).set_index('key')
left.join(right, lsuffix='_l', rsuffix='_r')

     val_l  val_r
key            
foo      1      4
bar      2      5

La même fonctionnalité peut être obtenue en utilisant mergeles colonnes suivantes:

left = pd.DataFrame({'key': ['foo', 'bar'], 'val': [1, 2]})
right = pd.DataFrame({'key': ['foo', 'bar'], 'val': [4, 5]})
left.merge(right, on=('key'), suffixes=('_l', '_r'))

   key  val_l  val_r
0  foo      1      4
1  bar      2      5
Paul H
la source
L'erreur semble dire qu'il s'attend à ce que le multi-index rightsoit à la même profondeur que la longueur on. Cela a du sens pour moi en quelque sorte. Je peux accepter que la sémantique soit différente. Mais j'aimerais savoir si je peux obtenir ce même comportement avec df.join
munk
346

pandas.merge() est la fonction sous-jacente utilisée pour tous les comportements de fusion / jointure.

Les DataFrames fournissent les méthodes pandas.DataFrame.merge()et pandas.DataFrame.join()comme un moyen pratique d'accéder aux capacités de pandas.merge(). Par exemple, df1.merge(right=df2, ...)est équivalent à pandas.merge(left=df1, right=df2, ...).

Ce sont les principales différences entre df.join()et df.merge():

  1. recherche sur la table de droite: df1.join(df2)joint toujours via l'index de df2, mais df1.merge(df2)peut se joindre à une ou plusieurs colonnes de df2(par défaut) ou à l'index de df2(avec right_index=True).
  2. recherche sur la table de gauche: par défaut, df1.join(df2)utilise l'index de df1et df1.merge(df2)utilise les colonnes de df1. Cela peut être annulé en spécifiant df1.join(df2, on=key_or_keys)ou df1.merge(df2, left_index=True).
  3. gauche contre jointure interne: df1.join(df2)effectue une jointure gauche par défaut (conserve toutes les lignes de df1), mais df.mergeeffectue une jointure interne par défaut (retourne uniquement les lignes correspondantes de df1et df2).

Donc, l'approche générique consiste à utiliser pandas.merge(df1, df2)ou df1.merge(df2). Mais pour un certain nombre de situations courantes (conserver toutes les lignes de df1et se joindre à un index df2), vous pouvez enregistrer une saisie en utilisant à la df1.join(df2)place.

Quelques notes sur ces problèmes dans la documentation à http://pandas.pydata.org/pandas-docs/stable/merging.html#database-style-dataframe-joining-merging :

merge est une fonction de l'espace de noms pandas, et elle est également disponible en tant que méthode d'instance DataFrame, le DataFrame appelant étant implicitement considéré comme l'objet gauche de la jointure.

La DataFrame.joinméthode associée , utilise en mergeinterne pour les jointures index-sur-index et index-sur-colonne (s), mais joint par défaut sur les index plutôt que d'essayer de se joindre sur des colonnes communes (le comportement par défaut pour merge). Si vous vous joignez à l'index, vous souhaiterez peut-être utiliser DataFrame.joinpour vous épargner de la frappe.

...

Ces deux appels de fonction sont totalement équivalents:

left.join(right, on=key_or_keys)
pd.merge(left, right, left_on=key_or_keys, right_index=True, how='left', sort=False)
Matthias Fripp
la source
19
Cela devrait certainement être la réponse acceptée! Merci pour l'explication détaillée
Yohan Obadia
@Matthias Fripp, peut-être pour les plus expérimentés, cela va sans dire, mais on pourrait également dire que "recherche sur la table de droite: df1.join (df2) peut être remplacé par df1.join (df2, on = key_or_keys?
spacedustpi
@spacedustpi, je pense que vous dites que vous pouvez utiliser on=key_or_keyspour changer la façon dont les lignes sont trouvées dans le bon tableau. Mais ce n'est pas vraiment le cas. L' onargument modifie la recherche sur la table de gauche ( df1) de l'index en colonne (s). Cependant, même avec cet argument, la bonne table ( df2) sera mise en correspondance via son index. (Voir le dernier exemple ci-dessus.)
Matthias Fripp
Pandas a plusieurs méthodes pour faire face à ces situations, parmi lesquelles fusionner, joindre, ajouter, concaténer, combiner, combine_first. Jetez un coup d'œil à chacun d'eux pour avoir un aperçu de celui qui conviendrait le mieux à votre situation
xiaxio
13

Je pense que ce join()n'est qu'une méthode pratique. Essayez df1.merge(df2)plutôt, ce qui vous permet de spécifier left_onet right_on:

In [30]: left.merge(right, left_on="key1", right_on="key2")
Out[30]: 
  key1  lval key2  rval
0  foo     1  foo     4
1  bar     2  bar     5
Noé
la source
11

De cette documentation

pandas fournit une fonction unique, la fusion, comme point d'entrée pour toutes les opérations de jointure de base de données standard entre les objets DataFrame:

merge(left, right, how='inner', on=None, left_on=None, right_on=None,
      left_index=False, right_index=False, sort=True,
      suffixes=('_x', '_y'), copy=True, indicator=False)

Et :

DataFrame.joinest une méthode pratique pour combiner les colonnes de deux DataFrames potentiellement indexés différemment en un seul DataFrame de résultat. Voici un exemple très basique: l'alignement des données se trouve ici sur les index (étiquettes de lignes). Ce même comportement peut être obtenu en utilisant la fusion et des arguments supplémentaires lui demandant d'utiliser les index:

result = pd.merge(left, right, left_index=True, right_index=True,
how='outer')
Romain Jouin
la source
8

L'une des différences est la mergecréation d'un nouvel index et la joinconservation de l'index du côté gauche. Cela peut avoir une grande conséquence sur vos transformations ultérieures si vous supposez à tort que votre index n'est pas modifié avec merge.

Par exemple:

import pandas as pd

df1 = pd.DataFrame({'org_index': [101, 102, 103, 104],
                    'date': [201801, 201801, 201802, 201802],
                    'val': [1, 2, 3, 4]}, index=[101, 102, 103, 104])
df1

       date  org_index  val
101  201801        101    1
102  201801        102    2
103  201802        103    3
104  201802        104    4

-

df2 = pd.DataFrame({'date': [201801, 201802], 'dateval': ['A', 'B']}).set_index('date')
df2

       dateval
date          
201801       A
201802       B

-

df1.merge(df2, on='date')

     date  org_index  val dateval
0  201801        101    1       A
1  201801        102    2       A
2  201802        103    3       B
3  201802        104    4       B

-

df1.join(df2, on='date')
       date  org_index  val dateval
101  201801        101    1       A
102  201801        102    2       A
103  201802        103    3       B
104  201802        104    4       B
steco
la source
C'est exact. Si nous fusionnons les deux blocs de données sur des colonnes autres que les indices, nous obtiendrons un nouvel index, mais si nous fusionnons sur les indices des deux blocs de données, nous obtiendrons le bloc de données avec le même indice. Ainsi, afin d'obtenir le même index après la fusion, nous pouvons faire des colonnes notre index (sur lequel nous voulons fusionner) pour les deux trames de données, puis fusionner les trames de données sur l'index nouvellement créé.
hasan najeeb
Très perspicace. Je n'ai jamais eu besoin de l'indexation (je ne fais normalement que réinitialiser l'index) mais cela pourrait faire une grande différence dans certains cas.
irene
4
  • Join: Index par défaut (si un nom de colonne est identique, il générera une erreur en mode par défaut car vous n'avez pas défini lsuffix ou rsuffix))
df_1.join(df_2)
  • Fusionner: mêmes noms de colonnes par défaut (s'il n'y a pas le même nom de colonne, cela générera une erreur en mode par défaut)
df_1.merge(df_2)
  • on le paramètre a une signification différente dans les deux cas
df_1.merge(df_2, on='column_1')

df_1.join(df_2, on='column_1') // It will throw error
df_1.join(df_2.set_index('column_1'), on='column_1')
Dur
la source
2

Pour le mettre de manière analogue à SQL, «la fusion Pandas est une jointure externe / interne et la jointure Pandas est une jointure naturelle». Par conséquent, lorsque vous utilisez la fusion dans pandas, vous souhaitez spécifier le type de jointure sqlish que vous souhaitez utiliser, tandis que lorsque vous utilisez la jointure pandas, vous voulez vraiment avoir une étiquette de colonne correspondante pour vous assurer qu'elle se joint

Kaustubh J
la source