Jak określić nazwy kolumn dla x i y podczas łączenia w dplyr?

89

Mam dwie ramki danych, które chcę połączyć za pomocą dplyr. Jedna to ramka danych zawierająca imiona.

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

Druga ramka danych zawiera uporządkowaną wersję korpusu nazw Kantrowitza, identyfikującą płeć. Oto minimalny przykład:

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"))

Zasadniczo chcę sprawdzić płeć nazwiska z test_datatabeli za pomocą kantrowitztabeli. Ponieważ zamierzam przekształcić to w funkcję encode_gender, nie będę znać nazwy kolumny w zestawie danych, który będzie używany, więc nie mogę zagwarantować, że tak będzie name, jak w kantrowitz$name.

W bazowym RI scaliłbym w ten sposób:

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

To zwraca poprawne dane wyjściowe:

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

Ale chcę to zrobić w dplyr, ponieważ używam tego pakietu do wszystkich innych operacji na danych. Opcja dplyr bydla różnych *_joinfunkcji pozwala mi określić tylko jedną nazwę kolumny, ale muszę określić dwie. Szukam czegoś takiego:

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"))

Jaki jest sposób wykonania tego rodzaju złączenia za pomocą dplyr?

(Nieważne, że korpus Kantrowitza to zły sposób na identyfikację płci. Pracuję nad lepszą implementacją, ale najpierw chcę, żeby to zadziałało).

Lincoln Mullen
źródło
3
Obecnie nie możesz, ale jest na liście rzeczy do zrobienia: github.com/hadley/dplyr/issues/177
hadley

Odpowiedzi:

148

Ta funkcja została dodana w dplyr v0.3. Możesz teraz przekazać nazwany wektor znakowy do byargumentu in left_join(i innych funkcji łączących), aby określić, które kolumny mają być połączone w każdej ramce danych. W przykładzie podanym w pierwotnym pytaniu kod wyglądałby tak:

left_join(test_data, kantrowitz, by = c("first_name" = "name"))
Lincoln Mullen
źródło
13
edytować w ogólnym przypadku to działa jak dobrze: left_join(data_a, data_b, by = c("a.first" = "b.first", "a.second" = "b.second", "a.third" = "b.third"))?
davidski
To by =jest opcjonalne. Możesz to zrobićleft_join(test_data, kantrowitz, c("first_name" = "name"))
Pranay Aryal
11
Dotyczy to każdego argumentu funkcji. Ale generalnie uważam, że lepiej jest być wyraźnym, używając nazwanych argumentów, zamiast dopasowywania pozycji w tym przypadku.
Lincoln Mullen
5

To bardziej obejście niż prawdziwe rozwiązanie. Możesz utworzyć nowy obiekt test_dataz inną nazwą kolumny:

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
źródło
Myślę, że zmiana nazwy wywołuje kopię, co może być sposobem, w jaki dplyr tego unika i sprawia, że ​​robisz to.
joran
2
W 0.1.2 przynajmniej będziesz w stanie to zrobić, select(test_data, first_name = name)a to będzie tylko płytką kopię.
hadley
1
Użyj data.table::setnames?
Hugh,
2
wybór rozwiązania (test_data, first_name = name) nie działa od czerwca 2014
userJT