Ce chapitre est en cours d’écriture.

Lorsqu’on traite de grosses enquêtes, notamment les enquêtes de l’INSEE, on a souvent à gérer des données réparties dans plusieurs tables, soit du fait de la construction du questionnaire, soit du fait de contraintes techniques (fichiers dbf ou Excel limités à 256 colonnes, par exemple).

Cela arrive également lorsque l’on traitre de données d’une enquêtes réalisée à différents niveaux (par exemple, un questionnaire ménage et un questionnaire individu).

La fonction merge

Une opération relativement courante consiste à fusionner plusieurs tables pour regrouper tout ou partie des données dans un unique tableau.

Nous allons simuler artificiellement une telle situation en créant deux tables à partir de l’extrait de l’enquête Histoire de vie :

library(questionr)
data(hdv2003)
d <- hdv2003
dim(d)
[1] 2000   20
d1 <- subset(d, select = c("id", "age", "sexe"))
dim(d1)
[1] 2000    3
d2 <- subset(d, select = c("id", "clso"))
dim(d2)
[1] 2000    2

On a donc deux tableaux de données, d1 et d2, comportant chacun 2000 lignes et respectivement 3 et 2 colonnes. Comment les rassembler pour n’en former qu’un ?

Intuitivement, cela paraît simple. Il suffit de « coller » d2 à la droite de d1, comme dans l’exemple suivant.

id v1 v2
1 H 12
2 H 17
3 F 41
4 F 9
+
id v3
1 rouge
2 bleu
3 bleu
4 rouge
=
id v1 v2 v3
1 H 12 rouge
2 H 17 bleu
3 F 41 bleu
4 F 9 rouge

Cela semble fonctionner. La fonction qui permet d’effectuer cette opération sous R s’appelle cbind, elle « colle » des tableaux côte à côte en regroupant leurs colonnes1.

head(cbind(d1, d2))
  id age  sexe id clso
1  1  28 Femme  1  Oui
2  2  23 Femme  2  Oui
3  3  59 Homme  3  Non
4  4  34 Homme  4  Non
5  5  71 Femme  5  Oui
6  6  35 Femme  6  Non

À part le fait qu’on a une colonne id en double, le résultat semble satisfaisant. À première vue seulement. Imaginons maintenant que nous avons travaillé sur d1 et d2, et que nous avons ordonné les lignes de d1 selon l’âge des enquêtés :

d1 <- d1[order(d1$age), ]

Répétons l’opération de collage :

head(cbind(d1, d2))
     id age  sexe id clso
162 162  18 Homme  1  Oui
215 215  18 Homme  2  Oui
346 346  18 Femme  3  Non
377 377  18 Homme  4  Non
511 511  18 Homme  5  Oui
646 646  18 Homme  6  Non

Que constate-t-on ? La présence de la variable id en double nous permet de voir que les identifiants ne coïncident plus ! En regroupant nos colonnes nous avons donc attribué à des individus les réponses d’autres individus.

La commande cbind ne peut en effet fonctionner que si les deux tableaux ont exactement le même nombre de lignes, et dans le même ordre, ce qui n’est pas le cas ici.

On va donc être obligé de pocéder à une fusion des deux tableaux, qui va permettre de rendre à chaque ligne ce qui lui appartient. Pour cela nous avons besoin d’un identifiant qui permet d’identifier chaque ligne de manière unique et qui doit être présent dans tous les tableaux. Dans notre cas, c’est plutôt rapide, il s’agit de la variable id.

Une fois l’identifiant identifié2, on peut utiliser la commande merge. Celle-ci va fusionner les deux tableaux en supprimant les colonnes en double et en regroupant les lignes selon leurs identifiants :

d.complet <- merge(d1, d2, by = "id")
head(d.complet)
  id age  sexe clso
1  1  28 Femme  Oui
2  2  23 Femme  Oui
3  3  59 Homme  Non
4  4  34 Homme  Non
5  5  71 Femme  Oui
6  6  35 Femme  Non

Ici l’utilisation de la fonction merge est plutôt simple car nous sommes dans le cas de figure idéal : les lignes correspondent parfaitement et l’identifiant est clairement identifié. Parfois les choses peuvent être un peu plus compliquées :

  • parfois les identifiants n’ont pas le même nom dans les deux tableaux. On peut alors les spécifier par les options by.x et by.y ;
  • parfois les deux tableaux comportent des colonnes (hors identifiants) ayant le même nom. merge conserve dans ce cas ces deux colonnes mais les renomme en les suffixant par .x pour celles provenant du premier tableau et .y pour celles du second ;
  • parfois on n’a pas d’identifiant unique préétabli, mais on en construit un à partir de plusieurs variables. On peut alors donner un vecteur en paramètres de l’option by, par exemple by=c("nom","prenom","date.naissance").

Une subtilité supplémentaire intervient lorsque les deux tableaux fusionnés n’ont pas exactement les mêmes lignes. Par défaut, merge ne conserve que les lignes présentes dans les deux tableaux :

id v1
1 H
2 H
3 F
+
id v2
1 10
2 15
5 31
=
id v1 v2
1 H 10
2 H 15

On peut cependant modifier ce comportement avec les options all.x et all.y.

Ainsi, all.x=TRUE indique de conserver toutes les lignes du premier tableau. Dans ce cas merge donne une valeur NA pour ces lignes aux colonnes provenant du second tableau. Ce qui donnerait :

id v1
1 H
2 H
3 F
+
id v2
1 10
2 15
5 31
=
id v1 v2
1 H 10
2 H 15
3 F NA

L’option all.y=TRUE fait la même chose en conservant toutes les lignes du second tableau.

id v1
1 H
2 H
3 F
+
id v2
1 10
2 15
5 31
=
id v1 v2
1 H 10
2 H 15
5 NA 31

Enfin, on peut décider de conserver toutes les lignes des deux tableaux en utilisant à la fois all.x=TRUE et all.y=TRUE, ce qui donne :

id v1
1 H
2 H
3 F
+
id v2
1 10
2 15
5 31
=
id v1 v2
1 H 10
2 H 15
3 F NA
5 NA 31

Parfois, l’un des identifiants est présent à plusieurs reprises dans l’un des tableaux (par exemple lorsque l’une des tables est un ensemble de ménages et que l’autre décrit l’ensemble des individus de ces ménages). Dans ce cas les lignes de l’autre table sont dupliquées autant de fois que nécessaires :

id v1
1 H
2 H
3 F
+
id v2
1 10
1 18
1 21
2 15
3 42
=
id v1 v2
1 H 10
1 H 18
1 H 21
2 H 15
3 F 42

Extension dplyr

Voir la vignette dédiée (en anglais) : https://cran.rstudio.com/web/packages/dplyr/vignettes/two-table.html.

Les principales fonctions de dplyr pour la fusion de tables sont inner_join et left_join.

Extension data.table

data.table fourni une fonction merge beaucoup plus rapide que celle standard de R mais fonctionnant de manière identique.


  1. L’équivalent de cbind pour les lignes s’appelle rbind.

  2. Si vous me passez l’expression…