1413 votes

Comment joindre (fusionner) des cadres de données (intérieur, extérieur, gauche, droite) ?

Étant donné deux cadres de données :

df1 = data.frame(CustomerId = c(1:6), Product = c(rep("Toaster", 3), rep("Radio", 3)))
df2 = data.frame(CustomerId = c(2, 4, 6), State = c(rep("Alabama", 2), rep("Ohio", 1)))

df1
#  CustomerId Product
#           1 Toaster
#           2 Toaster
#           3 Toaster
#           4   Radio
#           5   Radio
#           6   Radio

df2
#  CustomerId   State
#           2 Alabama
#           4 Alabama
#           6    Ohio

Comment puis-je faire du style base de données, c'est-à-dire, style sql, jointures ? C'est-à-dire, comment puis-je obtenir :

  • Un jointure intérieure de df1 y df2 :
    Renvoie uniquement les lignes dans lesquelles la table de gauche a des clés correspondantes dans la table de droite.
  • Un jointure extérieure de df1 y df2 :
    Renvoie toutes les lignes des deux tables, en joignant les enregistrements de gauche qui ont des clés correspondantes dans la table de droite.
  • A jointure externe gauche (ou simplement jointure gauche) de df1 y df2
    Renvoie toutes les lignes de la table de gauche, et toutes les lignes avec des clés correspondantes de la table de droite.
  • A jointure externe droite de df1 y df2
    Renvoie toutes les lignes de la table de droite, et toutes les lignes avec des clés correspondantes de la table de gauche.

Un crédit supplémentaire :

Comment puis-je faire une instruction de sélection de style SQL ?

4 votes

stat545-ubc.github.io/bit001_dplyr-cheatsheet.html ma réponse préférée à cette question

0 votes

L'aide-mémoire Data Transformation with dplyr créé et maintenu par RStudio contient également de belles infographies sur le fonctionnement des jointures dans dplyr. rstudio.com/ressources/cheatsheets

3 votes

Si vous êtes venu ici pour vous renseigner sur la fusion pandas cette ressource peut être trouvée aquí .

1530voto

Matt Parker Points 7373

En utilisant le merge et ses paramètres facultatifs :

Jointure intérieure : merge(df1, df2) fonctionnera pour ces exemples car R joint automatiquement les cadres par des noms de variables communs, mais vous voudrez très probablement spécifier merge(df1, df2, by = "CustomerId") pour vous assurer que vous ne faites correspondre que les champs que vous souhaitez. Vous pouvez également utiliser la fonction by.x y by.y si les variables correspondantes ont des noms différents dans les différentes trames de données.

Jointure extérieure : merge(x = df1, y = df2, by = "CustomerId", all = TRUE)

Extérieur gauche : merge(x = df1, y = df2, by = "CustomerId", all.x = TRUE)

Extérieur droit : merge(x = df1, y = df2, by = "CustomerId", all.y = TRUE)

Croisez les joints : merge(x = df1, y = df2, by = NULL)

Tout comme pour la jointure interne, vous voudrez probablement transmettre explicitement "CustomerId" à R comme variable de correspondance. Je pense qu'il est presque toujours préférable d'indiquer explicitement les identifiants sur lesquels vous voulez fusionner ; c'est plus sûr si les data.frames d'entrée changent de manière inattendue et plus facile à lire par la suite.

Vous pouvez fusionner sur plusieurs colonnes en donnant by un vecteur, par exemple, by = c("CustomerId", "OrderId") .

Si les noms des colonnes à fusionner ne sont pas les mêmes, vous pouvez spécifier, par exemple, by.x = "CustomerId_in_df1", by.y = "CustomerId_in_df2" donde CustomerId_in_df1 est le nom de la colonne dans le premier cadre de données et CustomerId_in_df2 est le nom de la colonne dans le deuxième cadre de données. (Il peut également s'agir de vecteurs si vous avez besoin de fusionner sur plusieurs colonnes).

2 votes

@MattParker J'ai utilisé le paquet sqldf pour toute une série de requêtes complexes contre des cadres de données, j'en avais vraiment besoin pour faire une jointure croisée automatique (c'est-à-dire que le cadre de données se joint lui-même de manière croisée). Je me demande comment il se compare du point de vue des performances.... ???

9 votes

@ADP Je n'ai jamais vraiment utilisé sqldf, donc je ne suis pas sûr de la vitesse. Si les performances sont un problème majeur pour vous, vous devriez également vous pencher sur l'option data.table Il s'agit d'un tout nouvel ensemble de syntaxe de jointure, mais il est radicalement plus rapide que tout ce dont nous parlons ici.

5 votes

Avec plus de clarté et d'explication..... mkmanu.wordpress.com/2016/04/08/

245voto

medriscoll Points 4479

Je vous recommande de vérifier Le paquet sqldf de Gabor Grothendieck qui vous permet d'exprimer ces opérations en SQL.

library(sqldf)

## inner join
df3 <- sqldf("SELECT CustomerId, Product, State 
              FROM df1
              JOIN df2 USING(CustomerID)")

## left join (substitute 'right' for right join)
df4 <- sqldf("SELECT CustomerId, Product, State 
              FROM df1
              LEFT JOIN df2 USING(CustomerID)")

Je trouve la syntaxe SQL plus simple et plus naturelle que son équivalent R (mais cela reflète peut-être mon penchant pour les SGBDR).

Ver GitHub sqldf de Gabor pour plus d'informations sur les jointures.

222voto

Il y a le table.de.données pour une jointure interne, qui est très efficace en termes de temps et de mémoire (et nécessaire pour certains cadres de données plus grands) :

library(data.table)

dt1 <- data.table(df1, key = "CustomerId") 
dt2 <- data.table(df2, key = "CustomerId")

joined.dt1.dt.2 <- dt1[dt2]

merge fonctionne également sur data.tables (car il est générique et appelle merge.data.table )

merge(dt1, dt2)

data.table documenté sur stackoverflow :
Comment effectuer une opération de fusion data.table ?
Traduction des jointures SQL sur les clés étrangères en syntaxe R data.table
Alternatives efficaces à la fusion pour les cadres de données plus grands R
Comment faire une jointure extérieure gauche de base avec data.table en R ?

Une autre option encore est le join qui se trouve dans le plyr paquet

library(plyr)

join(df1, df2,
     type = "inner")

#   CustomerId Product   State
# 1          2 Toaster Alabama
# 2          4   Radio Alabama
# 3          6   Radio    Ohio

Options pour type : inner , left , right , full .

De ?join : Contrairement à merge , [ join ] préserve l'ordre de x quel que soit le type de jointure utilisé.

9 votes

+1 pour la mention plyr::join . Le microbenchmarking indique qu'elle est environ 3 fois plus rapide que merge .

23 votes

Cependant, data.table est beaucoup plus rapide que les deux. Il y a aussi un grand soutien dans l'OS, je ne vois pas beaucoup de rédacteurs de paquets répondre aux questions ici aussi souvent que dans l'OS. data.table l'auteur ou les collaborateurs.

1 votes

Quel est le data.table syntaxe pour fusionner un liste des cadres de données ?

215voto

Andrew Barr Points 491

Vous pouvez aussi faire des jointures en utilisant l'impressionnante méthode de Hadley Wickham. dplyr paquet.

library(dplyr)

#make sure that CustomerId cols are both type numeric
#they ARE not using the provided code in question and dplyr will complain
df1$CustomerId <- as.numeric(df1$CustomerId)
df2$CustomerId <- as.numeric(df2$CustomerId)

Mutations de jointures : ajouter des colonnes à df1 en utilisant des correspondances dans df2

#inner
inner_join(df1, df2)

#left outer
left_join(df1, df2)

#right outer
right_join(df1, df2)

#alternate right outer
left_join(df2, df1)

#full join
full_join(df1, df2)

Filtrage des jointures : filtrer les lignes dans df1, ne pas modifier les colonnes

semi_join(df1, df2) #keep only observations in df1 that match in df2.
anti_join(df1, df2) #drops all observations in df1 that match in df2.

18 votes

Pourquoi devez-vous convertir CustomerId en numérique ? Je ne vois aucune mention dans la documentation (tant pour les plyr y dplyr ) sur ce type de restriction. Votre code fonctionnerait-il de manière incorrecte, si la colonne de fusion était de type character (particulièrement intéressé par plyr ) ? Est-ce que quelque chose m'échappe ?

0 votes

Pourrait-on utiliser semi_join(df1, df2, df3, df4) pour ne garder que les observations de df1 qui correspondent au reste des colonnes ?

0 votes

@GhoseBishwajit En supposant que vous voulez parler du reste des cadres de données au lieu des colonnes, vous pouvez utiliser rbind sur df2, df3 et df4 s'ils ont la même structure, par exemple semi_join(df1, rbind(df2, df3, df4)).

99voto

JD Long Points 20477

Vous trouverez de bons exemples de cette démarche sur le site de la R Wiki . Je vais en voler quelques-uns ici :

Méthode de fusion

Puisque vos clés sont nommées de la même façon, le moyen le plus court de faire une jointure interne est merge() :

merge(df1,df2)

une jointure interne complète (tous les enregistrements des deux tables) peut être créée avec le mot clé "all" :

merge(df1,df2, all=TRUE)

une jointure externe gauche de df1 et df2 :

merge(df1,df2, all.x=TRUE)

une jointure externe droite de df1 et df2 :

merge(df1,df2, all.y=TRUE)

vous pouvez les retourner, les gifler et les frotter pour obtenir les deux autres joints extérieurs dont vous parliez :)

Méthode de l'indice

Une jointure externe gauche avec df1 à gauche en utilisant la méthode des indices serait la suivante :

df1[,"State"]<-df2[df1[ ,"Product"], "State"]

L'autre combinaison de jointures externes peut être créée en modifiant l'exemple de l'indice de jointure externe gauche. (oui, je sais que c'est l'équivalent de dire "je laisse cela comme un exercice pour le lecteur...")

4 votes

Le lien "R Wiki" est cassé.

0 votes

Ca devrait être : "Smack it up, flip it, rub it down", mais c'est un bon effort. ;-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X