Il y a quelques mois, je postais un billet concernant la manipulation de tableaux de données avec dplyr, concernant plus particulièrement la réalisation de 5 opérations de base sur des tableaux (sélection de colonnes avec select(), filtrage de lignes avec filter, réarrangement des lignes avec arrange, création ou modification de colonnes avec mutate, et synthétisation statistique avec summarise).

Aujourd'hui, je vais aborder un type d'opération différent, à savoir, les jointures de tableaux (i.e., grosso modo, comment "coller" deux tableaux ensemble pour en faire un seul).

Pour ce faire, plutôt que de faire mes propres petits graphiques explicatifs (aussi beaux et roses soient-ils), je vais utiliser ceux fournis par RStudio et (plus particulièrement) Garrett Grolemund dans leur cheatsheet concernant la transformation de données avec dplyr. Merci à eux, donc, d'abord pour avoir créé cette "antisèche" très utile, et ensuite pour m'avoir autorisée à la découper en petits morceaux et la réutiliser à l'envi ?...

Avant toute chose, chargeons donc le package dplyr:

library(dplyr)

Combinaison de deux tableaux

Dans une version très très simple, on peut simplement accoler ensemble deux tableaux, soit en colonnes (avec bind_cols()), soit en lignes (avec bind_rows).

Accolement de deux tableaux, en colonnes:

Dans ce premier cas, il est évidemment nécessaire que les individus (et l'ordre dans lequel ils apparaissent dans les deux tables) correspondent.

Avec les deux tables x et y:

bind_cols(x, y)

##   A B C A1 B1 D
## 1 a t 1  a  t 3
## 2 b u 2  b  u 2
## 3 c v 3  d  w 1

Les noms de variables de la deuxième table, y, sont ici modifiées pour éviter que plusieurs variables aient le même nom.

Accolement de deux tableaux, en lignes:

Dans ce second cas, il est nécessaire que les variables (et l'ordre dans lequel elles apparaissent) correspondent.

bind_rows(x,z)

##   A B C
## 1 a t 1
## 2 b u 2
## 3 c v 3
## 4 c v 3
## 5 d w 4

Si l'on souhaite conserver une trace, dans le tableau final, de l'origine des informations, on peut rajouter un identifiant de tableau de la manière suivante:

bind_rows(x,z,.id="myID")

##   myID A B C
## 1    1 a t 1
## 2    1 b u 2
## 3    1 c v 3
## 4    2 c v 3
## 5    2 d w 4

Par défaut, les identifiants seront simplement 1 et 2.

Si vous souhaitez spécifier des identifiants différents (par exemple, "x", et "z" plutôt que 1 et 2), vous pouvez procéder comme suit:

bind_rows(list(x=x,z=z), .id="myID")

##   myID A B C
## 1    x a t 1
## 2    x b u 2
## 3    x c v 3
## 4    z c v 3
## 5    z d w 4

Il est également possible d'accoler deux tableaux en lignes en utilisant l'idée d'union, d'intersection et de différence...

"Intersection" de deux tableaux

intersect(x,z)

##   A B C
## 1 c v 3

Dans le cas d'une intersection, on ne retient que les individus communs aux deux tableaux.

"Union" de deux tableaux

union(x,z)

##   A B C
## 1 c v 3
## 2 a t 1
## 3 b u 2
## 4 d w 4

A la différence d'un simple appel à bind_rows(), union() retire les lignes redondantes.

"Différence" de deux tableaux

setdiff(x,z)

##   A B C
## 1 a t 1
## 2 b u 2

setdiff() ne retient que les lignes qui apparaissent dans le premier tableau et non dans le second.

Jointures

Dans une jointure, on "colle ensemble" des tableaux dont les lignes ne correspondent pas forcément (par exemple, à une information située en ligne 33 du premier tableau, correspond une information située en ligne 158 du deuxième tableau).

On peut distinguer plusieurs types de jointures.

Jointure à gauche

Dans une jointure à gauche, on adjoint aux informations de la table de gauche les informations issues de la table de droite:

left_join(x,y)

## Joining, by = c("A", "B")

##   A B C  D
## 1 a t 1  3
## 2 b u 2  2
## 3 c v 3 NA

Ainsi, c'est le tableau de gauche qui définit les individus du tableau en sortie (quand bien-même il n'y a pas d'information à leur sujet dans le tableau de droite: remarquez ainsi la donnée manquante dans la colonne D pour le 3ième individu...)

En mettant un peu de bazar dans les tables (autant que possible dans une table de 3 lignes ?),

x_mess=x[c(3,2,1),]
print(x_mess)

##   A B C
## 3 c v 3
## 2 b u 2
## 1 a t 1

y_mess=y[c(1,3,2),]
print(y_mess)

##   A B D
## 1 a t 3
## 3 d w 1
## 2 b u 2

on voit mieux l'intérêt de la jointure : voyez donc comme elle a bien sur faire le lien entre les deux tables malgré le bazar qu'on y a mis:

left_join(x_mess,y_mess)

## Joining, by = c("A", "B")

##   A B C  D
## 1 c v 3 NA
## 2 b u 2  2
## 3 a t 1  3

Ici, on n'a pas précisé pas quelle ligne de x allait avec quelle ligne de y: de ce fait, la fonction a simplement supposé que les variables communes aux deux tableaux (ici A et B) permettaient d'identifier les individus et de relier les informations des deux tables.

Il est bien sûr possible (voire recommandé) de préciser explicitement quelles sont les identifiants qui permettent de faire ce lien entre les deux tables, à travers l'argument by:

left_join(x,y, by=c("A","B"))

##   A B C  D
## 1 a t 1  3
## 2 b u 2  2
## 3 c v 3 NA

Jointure à droite

Dans une jointure à droite, on adjoint aux informations de la table de droite les informations issues de la table de gauche.

right_join(x,y,by=c("A","B"))

##   A B  C D
## 1 a t  1 3
## 2 b u  2 2
## 3 d w NA 1

Ainsi, c'est le tableau de droite qui définit les individus du tableau en sortie (quand bien-même le tableau de gauche ne contiendrait pas d'informations à leur sujet: remarquez ainsi la donnée manquante dans la colonne C pour le 3ième individu... ).

Jointure interne

Dans une jointure interne, ne sont conservés que les individus communs aux deux jeux de données:

inner_join(x,y,by=c("A","B"))

##   A B C D
## 1 a t 1 3
## 2 b u 2 2

Jointure complète

Dans le cas d'une jointure complète, au contraire d'une jointure interne, on conserve l'ensemble des individus décrits par l'un ou l'autre des jeux de données...

full_join(x,y,by=c("A","B"))

##   A B  C  D
## 1 a t  1  3
## 2 b u  2  2
## 3 c v  3 NA
## 4 d w NA  1

Identifiants portant des noms différents

Il arrive qu'une variable identifiant les individus n'ait pas le même nom dans les deux tableaux... Dans ce cas on peut préciser de faire correspondre à une variable du premier tableau, une autre variable du deuxième tableau, de la manière suivante:

# Fait correspondre x$C et y$D:
full_join(x,y,by=c("C"="D"))

##   A.x B.x C A.y B.y
## 1   a   t 1   d   w
## 2   b   u 2   b   u
## 3   c   v 3   a   t