Comment spécifier les noms des colonnes pour x et y lors de la connexion à dplyr?

89

J'ai deux trames de données que je veux joindre en utilisant dplyr. L'un est un bloc de données contenant les prénoms.

test_data <- data.frame(first_name = c("john", "bill", "madison", "abby", "zzz"),
                        stringsAsFactors = FALSE)

L'autre bloc de données contient une version nettoyée du corpus des noms de Kantrowitz, identifiant le sexe. Voici un exemple minimal:

kantrowitz <- structure(list(name = c("john", "bill", "madison", "abby", "thomas"), gender = c("M", "either", "M", "either", "M")), .Names = c("name", "gender"), row.names = c(NA, 5L), class = c("tbl_df", "tbl", "data.frame"))

Je veux essentiellement rechercher le sexe du nom de la test_datatable en utilisant la kantrowitztable. Parce que je vais résumer cela dans une fonction encode_gender, je ne connais pas le nom de la colonne dans l'ensemble de données qui va être utilisé, et donc je ne peux pas garantir qu'elle le sera name, comme dans kantrowitz$name.

Dans la base, RI effectuerait la fusion de cette façon:

merge(test_data, kantrowitz, by.x = "first_names", by.y = "name", all.x = TRUE)

Cela renvoie la sortie correcte:

  first_name gender
1       abby either
2       bill either
3       john      M
4    madison      M
5        zzz   <NA>

Mais je veux faire cela dans dplyr parce que j'utilise ce package pour toutes mes autres manipulations de données. L' byoption dplyr pour les différentes *_joinfonctions ne me permet de spécifier qu'un seul nom de colonne, mais je dois en spécifier deux. Je cherche quelque chose comme ça:

library(dplyr)
# either
left_join(test_data, kantrowitz, by.x = "first_name", by.y = "name")
# or
left_join(test_data, kantrowitz, by = c("first_name", "name"))

Comment effectuer ce type de jointure en utilisant dplyr?

(Peu importe que le corpus Kantrowitz soit un mauvais moyen d'identifier le genre. Je travaille sur une meilleure implémentation, mais je veux que cela fonctionne en premier.)

Lincoln Mullen
la source
3
Vous ne pouvez pas actuellement, mais c'est sur la liste des choses à faire: github.com/hadley/dplyr/issues/177
hadley

Réponses:

148

Cette fonctionnalité a été ajoutée dans dplyr v0.3. Vous pouvez maintenant passer un vecteur de caractère nommé à l' byargument dans left_join(et à d'autres fonctions de jointure) pour spécifier les colonnes à joindre dans chaque bloc de données. Avec l'exemple donné dans la question initiale, le code serait:

left_join(test_data, kantrowitz, by = c("first_name" = "name"))
Lincoln Mullen
la source
13
modifier Cela fonctionne dans le cas général ainsi: left_join(data_a, data_b, by = c("a.first" = "b.first", "a.second" = "b.second", "a.third" = "b.third"))?
davidski
Le by =est facultatif. Vous pouvez faireleft_join(test_data, kantrowitz, c("first_name" = "name"))
Pranay Aryal
11
C'est vrai pour tout argument à une fonction. Mais je trouve généralement qu'il vaut mieux être explicite en utilisant des arguments nommés plutôt que la correspondance de position dans ce cas.
Lincoln Mullen
5

C'est plus une solution de contournement qu'une vraie solution. Vous pouvez créer un nouvel objet test_dataavec un autre nom de colonne:

left_join("names<-"(test_data, "name"), kantrowitz, by = "name")

     name gender
1    john      M
2    bill either
3 madison      M
4    abby either
5     zzz   <NA>
Sven Hohenstein
la source
Renommer induit une copie, je pense, ce qui peut être une façon pour dplyr de l'éviter et de vous le faire à la place.
joran
2
Dans la version 0.1.2, vous pourrez au moins le faire select(test_data, first_name = name)et cela ne fera qu'une copie superficielle.
hadley
1
Utiliser data.table::setnames?
Hugh
2
la solution select (test_data, first_name = name) ne fonctionne pas à partir de juin 2014
userJT