Fusionner deux tableaux des données par leurs colonnes : les jointures

Lorsqu’on analyse des données, il peut arriver qu’on ait besoin de fusionner les lignes de plusieurs tableaux de données (data frames), pour constituer un seul grand tableau de données.

 

Mais, parfois, ce ne sont pas les lignes que l’on a besoin d’assembler, mais les colonnes. Et comme pour la fusion des lignes, cet assemblage des colonnes de deux jeux de données (appelé aussi jointures) peut être réalisé de différentes façons. Par exemple, il peut s’agir d’une simple juxtaposition des colonnes (ce qui est rarement intéressant), ou bien il peut s’agir d’un appariement des colonnes, c’est à dire avec prise en compte d’une variable qui va permettre de relier (ou de joindre) les valeurs d’une colonne du premier jeu de données avec les valeurs correspondantes d’une colonne du second jeu de données. Cette fois encore, le package dplyr propose plusieurs fonctions permettant de réaliser des  jointures (fusions deux tableaux de données par leurs colonnes).
joindre deux jeux de données
D’après la cheat sheet du package dplyr

Ce sont ces fonctions que nous allons explorer dans cet article.

Premier exemple : une seule variable de jointure

Les data

Considérons un premier jeu de données, nommé “fish” qui contient les quantités de poissons (en tonnes) péchés pour une année donnée, par la Belgique, le Danemark, la Croatie, l’Estonie, la Grèce, et la Finlande.

print(fish)

    ##        geo   Capture
    ## 1 Belgique  26860.00
    ## 2 Danemark 670212.83
    ## 3  Croatie  72865.34
    ## 4  Estonie  72421.83
    ## 5    Grèce        NA
    ## 6 Finlande 164833.42 

Considérons également, un second jeu de données, nommé “bio” qui, lui, contient les superficies de cultures agricoles biologiques déclarées par la Belgique, le Danemark et de la Croatie, mais aussi (alors que ce n’est pas le cas du jeu de données “fish”) de la Norvège, du Portugal et de la Turquie.

print(bio)

    ##        geo SurfaceBio
    ## 1 Belgique      56055
    ## 2 Danemark     161251
    ## 3  Croatie      29172
    ## 4  Norvège      44681
    ## 5 Portugal     171743
    ## 6  Turquie     388547 

Juxtaposition des colonnes

Une première façon de vouloir joindre ces deux jeux de données peut simplement consister à les “coller” l’un à côté de l’autre. Pour cela, on peut utiliser la fonction bind_cols().

library(tidyverse)
data1 <- bind_cols(fish, bio)  
print(data1)

    ##        geo   Capture     geo1 SurfaceBio
    ## 1 Belgique  26860.00 Belgique      56055
    ## 2 Danemark 670212.83 Danemark     161251
    ## 3  Croatie  72865.34  Croatie      29172
    ## 4  Estonie  72421.83  Norvège      44681
    ## 5    Grèce        NA Portugal     171743
    ## 6 Finlande 164833.42  Turquie     388547 

On peut voir ici que les 2 colonnes du data frame “fish” ont été juxtaposées aux 2 colonnes du data frame “bio”, et que la deuxième variable “geo” a été renommée “geo1”.

En regardant le data frame obtenu, on peut voir que si les données Capture et SurfaceBio des trois premières lignes concernent les mêmes pays, cela n’est plus le cas pour les trois lignes suivantes, puisque les données de pêche concernent l’Estonie, la Grèce et la Finlande et que les données de surfaces agricoles biologiques concernent la Norvège, le Portugal et la Turquie.

Ce n’est pas forcément ce que l’on souhaite !

Les jointures

Jointures à gauche

La jointure à gauche est réalisée avec la fonction left_join(). Cette fonction prend en argument les deux data frames à fusionner, ainsi que la variable de jointure (ou appariement).

left_join(df1, df2, by"var_jointure") 

Dans la jointure à gauche, le premier data frame cité dans la fonction (celui qui est donc à gauche), est le data frame de référence. Ce sont les colonnes du second data frame (celui qui est à droite dans la fonction) qui vont être ajoutées au data frame de référence. Mais seules les valeurs des lignes correspondant aux modalités de la variable de jointure présentes dans le data frame de référence seront ajoutées. C’est un peu complexe à formuler alors qu’en pratique, c’est plutôt simple. Voici un exemple pour mieux comprendre. On réalise une fusion à gauche entre les data frame ‘fish” et “bio”, en considérant le pays (variable “géo”), comme variable de jointure :

data2 <-left_join(fish, bio, by="geo")
print(data2)

    ##        geo   Capture SurfaceBio
    ## 1 Belgique  26860.00      56055
    ## 2 Danemark 670212.83     161251
    ## 3  Croatie  72865.34      29172
    ## 4  Estonie  72421.83         NA
    ## 5    Grèce        NA         NA
    ## 6 Finlande 164833.42         NA 

Le jeu de données “bio” ne contenant pas de valeur pour l’Estonie, la Grèce et la Finlande, des NA ont été ajoutées.

Remarque : si aucune variable de jointure n’est fournie à la fonction, l’appariement va être réalisé sur le plus grand nombre de variables commune (dans cet exemple, uniquement “geo”) .

data2_bis <-left_join(fish, bio)
print(data2_bis)

    ##        geo   Capture SurfaceBio
    ## 1 Belgique  26860.00      56055
    ## 2 Danemark 670212.83     161251
    ## 3  Croatie  72865.34      29172
    ## 4  Estonie  72421.83         NA
    ## 5    Grèce        NA         NA
    ## 6 Finlande 164833.42         NA 

Jointure à droite

La jointure à droite est réalisée avec la fonction right_join(). Son principe est identique, sauf qu’ici le data.frame de référence est celui entré en deuxième position (ici bio).

data3 <- right_join(fish, bio)
print (data3)

    ##        geo   Capture SurfaceBio
    ## 1 Belgique  26860.00      56055
    ## 2 Danemark 670212.83     161251
    ## 3  Croatie  72865.34      29172
    ## 4  Norvège        NA      44681
    ## 5 Portugal        NA     171743
    ## 6  Turquie        NA     388547
Cette fois, ce sont les données de Surface biol 

Cette fois, ce sont les données de Surface biologiques qui sont complètes et les données de pêche de la Norvège, du Portugal et de la Turquie, qui ont été remplacées par des NA, car elles sont absentes du data frame “fish”.

Jointure restreinte

Une autre façon de fusionner les deux jeux de données, peut consister à ne considérer que les modalités communes de la variable de jointure (“geo”) présentes dans les deux data frames (ici la Belgique, le Danemark et la Croatie). Ce type de fusion est réalisé avec la fonction inner_join()

data4  <- inner_join(fish, bio, by="geo")
print(data4)

    ##        geo   Capture SurfaceBio
    ## 1 Belgique  26860.00      56055
    ## 2 Danemark 670212.83     161251
    ## 3  Croatie  72865.34      29172 

Jointure complète

Une dernière façon de fusionner les deux jeux de données, peut consister à considérer l’ensemble des modalités de la variable de jointure (“geo”), celles qui sont communes aux deux jeux de données (ici la Belgique, le Danemark et la Croatie) et celles qui sont uniquement présentes dans l’un des deux jeux de données. Ce type de fusion est réalisé avec la fonction full_join() :

data5<- full_join(fish,bio)
print(data5)

    ##        geo   Capture SurfaceBio
    ## 1 Belgique  26860.00      56055
    ## 2 Danemark 670212.83     161251
    ## 3  Croatie  72865.34      29172
    ## 4  Estonie  72421.83         NA
    ## 5    Grèce        NA         NA
    ## 6 Finlande 164833.42         NA
    ## 7  Norvège        NA      44681
    ## 8 Portugal        NA     171743
    ## 9  Turquie        NA     388547 

Dans ce type de fusion, les deux data frames sont considérés sur le même plan, toutes les modalités de la variable d’ajustement, des deux data frames, sont considérées.

Second exemple : plusieurs variables de jointures

Les data

Considérons, à présent, le même fichier “fish”, mais avec en plus une variable “Year”, fixée à 2016 pour toutes les lignes. Ce jeu de donnée est renommé “fish_16”.

print(fish_16)

    ##        geo   Capture Year
    ## 1 Belgique  26860.00 2016
    ## 2 Danemark 670212.83 2016
    ## 3  Croatie  72865.34 2016
    ## 4  Estonie  72421.83 2016
    ## 5    Grèce        NA 2016
    ## 6 Finlande 164833.42 2016 

Considérons aussi un nouveau jeu de données, concernant les surfaces agricoles biologiques. Ce nouveau jeu de données, nommé “bio_16_17” contient les superficies de cultures agricoles biologiques de la Belgique, du Danemark et de la Croatie pour l’année 2016, et celles de l’Estonie, de la Grèce et du Portugal, pour l’année 2017:

print(bio_16_17)

    ##        geo SurfaceBio Year
    ## 1 Belgique      56055 2016
    ## 2 Danemark     161251 2016
    ## 3  Croatie      29172 2016
    ## 4  Estonie     160837 2017
    ## 5    Grèce     280733 2017
    ## 6 Portugal     216180 2017 

Examinons, comment se déroulent la juxtaposition et les jointures lorsque deux variables de jointure sont présentes :

Juxtaposition des colonnes

bind_cols(fish_16, bio_16_17)

    ##        geo   Capture Year     geo1 SurfaceBio Year1
    ## 1 Belgique  26860.00 2016 Belgique      56055  2016
    ## 2 Danemark 670212.83 2016 Danemark     161251  2016
    ## 3  Croatie  72865.34 2016  Croatie      29172  2016
    ## 4  Estonie  72421.83 2016  Estonie     160837  2017
    ## 5    Grèce        NA 2016    Grèce     280733  2017
    ## 6 Finlande 164833.42 2016 Portugal     216180  2017 

Dans le cas de la juxtapositionrien de nouveau, si ce n’est que cette fois, ce sont les 3 colonnes du data frame bio_16_17 qui ont été “collées” aux 3 colonnes du data frame bio_16_17.

Les jointures

Jointure à gauche

Comme mentionné précédemment, lorsque aucune variable de jointure n’est passée en argument, les fonctions x_join() utilisent, par défaut le maximum de variables de jointure (ici “geo” et “Year”).

mydata1 <- left_join(fish_16, bio_16_17)
print(mydata1)

    ##        geo   Capture Year SurfaceBio
    ## 1 Belgique  26860.00 2016      56055
    ## 2 Danemark 670212.83 2016     161251
    ## 3  Croatie  72865.34 2016      29172
    ## 4  Estonie  72421.83 2016         NA
    ## 5    Grèce        NA 2016         NA
    ## 6 Finlande 164833.42 2016         NA 

Pour le vérifier, on peut passer “geo” et “Year” comme variables de jointure:

mydata1 <- left_join(fish_16, bio_16_17, by=c("geo", "Year"))
print(mydata1)

    ##        geo   Capture Year SurfaceBio
    ## 1 Belgique  26860.00 2016      56055
    ## 2 Danemark 670212.83 2016     161251
    ## 3  Croatie  72865.34 2016      29172
    ## 4  Estonie  72421.83 2016         NA
    ## 5    Grèce        NA 2016         NA
    ## 6 Finlande 164833.42 2016         NA 

Les valeurs de Surface de cultures biologiques pour l’Estonie, la Grèce et la Finlande n’ont pas été renseignées, car elles sont relatives à l’année 2017. Elle ont donc été remplacées par des NA.

Remarque : puisque en l’absence de variable d’appariement, celle-ci se réalise, par défaut, sur l’ensemble des variables disponible, si l’on souhaite une jointure uniquement sur le pays, il est nécessaire de le préciser :

mydata1_bis <- left_join(fish_16, bio_16_17, by=c("geo"))
print(mydata1_bis)

    ##        geo   Capture Year.x SurfaceBio Year.y
    ## 1 Belgique  26860.00   2016      56055   2016
    ## 2 Danemark 670212.83   2016     161251   2016
    ## 3  Croatie  72865.34   2016      29172   2016
    ## 4  Estonie  72421.83   2016     160837   2017
    ## 5    Grèce        NA   2016     280733   2017
    ## 6 Finlande 164833.42   2016         NA     NA 

On voit que dans ce cas, la variable Year a été conservé pour les deux jeux de données, ce qui est plus prudent !

Jointure à droite

mydata3 <- right_join(fish_16, bio_16_17)
print(mydata3)

    ##        geo   Capture Year SurfaceBio
    ## 1 Belgique  26860.00 2016      56055
    ## 2 Danemark 670212.83 2016     161251
    ## 3  Croatie  72865.34 2016      29172
    ## 4  Estonie        NA 2017     160837
    ## 5    Grèce        NA 2017     280733
    ## 6 Portugal        NA 2017     216180 

Ici, se sont les données de pêche qui n’ont pas été complétées puisqu’elle concernent l’année 2016 alors qu’il s’agit de l’année 2017 dans le tableau qui sert de référence (bio_16_17).

Jointure restreinte

mydata4 <- inner_join(fish_16, bio_16_17)
print(mydata4)

    ##        geo   Capture Year SurfaceBio
    ## 1 Belgique  26860.00 2016      56055
    ## 2 Danemark 670212.83 2016     161251
    ## 3  Croatie  72865.34 2016      29172 

Jointure complète

mydata5 <- full_join(fish_16, bio_16_17)
print(mydata5)

    ##        geo   Capture Year SurfaceBio
    ## 1 Belgique  26860.00 2016      56055
    ## 2 Danemark 670212.83 2016     161251
    ## 3  Croatie  72865.34 2016      29172
    ## 4  Estonie  72421.83 2016         NA
    ## 5    Grèce        NA 2016         NA
    ## 6 Finlande 164833.42 2016         NA
    ## 7  Estonie        NA 2017     160837
    ## 8    Grèce        NA 2017     280733
    ## 9 Portugal        NA 2017     216180 

Voilà ! J’espère que l’exploration de ces fonctions left_join(), right_join(), inner_join() et full_join(), avec une et plusieurs variables de jointure, vous a permis de mieux comprendre ce processus de fusion de deux jeux de données par leurs colonnes.

Si cet article vous a plu, ou vous a été utile, et si vous le souhaitez, vous pouvez soutenir ce blog en faisant un don sur sa page Tipeee 🙏

Crédits photos : OpenClipart-vectors

Une réponse

  1. Merci encore Claire, tu nous délivres ainsi des maux de tête que nous vivons lors du traitement de nos données. Je tiens vraiment à vous féliciter.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *