¿Cómo especificar los nombres de las columnas para xey al unirse en dplyr?

89

Tengo dos marcos de datos que quiero unir usando dplyr. Uno es un marco de datos que contiene nombres.

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

El otro marco de datos contiene una versión limpia del corpus de nombres de Kantrowitz, identificando el género. Aquí hay un ejemplo mínimo:

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

Básicamente, quiero buscar el género del nombre de la test_datatabla usando la kantrowitztabla. Como voy a abstraer esto en una función encode_gender, no sabré el nombre de la columna en el conjunto de datos que se usará, por lo que no puedo garantizar que así sea name, como en kantrowitz$name.

En base, RI realizaría la fusión de esta manera:

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

Eso devuelve la salida correcta:

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

Pero quiero hacer esto en dplyr porque estoy usando ese paquete para todas mis otras manipulaciones de datos. La byopción dplyr para las diversas *_joinfunciones solo me permite especificar un nombre de columna, pero necesito especificar dos. Estoy buscando algo como esto:

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

¿Cuál es la forma de realizar este tipo de unión utilizando dplyr?

(No importa que el corpus de Kantrowitz sea una mala manera de identificar el género. Estoy trabajando en una mejor implementación, pero primero quiero que esto funcione).

Lincoln Mullen
fuente
3
Actualmente no puede, pero está en la lista de tareas pendientes
hadley

Respuestas:

148

Esta función se ha agregado en dplyr v0.3. Ahora puede pasar un vector de caracteres con nombre al byargumento en left_join(y otras funciones de unión) para especificar en qué columnas unirse en cada marco de datos. Con el ejemplo dado en la pregunta original, el código sería:

left_join(test_data, kantrowitz, by = c("first_name" = "name"))
Lincoln Mullen
fuente
13
editar Esto también funciona en el caso general left_join(data_a, data_b, by = c("a.first" = "b.first", "a.second" = "b.second", "a.third" = "b.third")):?
Davidski
El by =es opcional. Puedes hacerloleft_join(test_data, kantrowitz, c("first_name" = "name"))
Pranay Aryal
11
Eso es cierto para cualquier argumento de una función. Pero en general encuentro mejor ser explícito usando argumentos con nombre en lugar de la coincidencia de posiciones en este caso.
Lincoln Mullen
5

Esto es más una solución temporal que una solución real. Puede crear un nuevo objeto test_datacon otro nombre de columna:

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
fuente
El cambio de nombre induce una copia, creo, que puede ser la forma en que dplyr lo evita y te obliga a hacerlo.
joran
2
En 0.1.2 al menos podrás hacerlo select(test_data, first_name = name)y eso solo hará una copia superficial.
hadley
1
Uso data.table::setnames?
Hugh
2
la selección de solución (test_data, first_name = name) no funciona a partir de junio de 2014
userJT