Reemplazar valores en un dataframe basado en la tabla de búsqueda

Tengo problemas para reemplazar los valores en un dataframe. Me gustaría reemplazar valores basados ​​en una tabla separada. A continuación se muestra un ejemplo de lo que estoy tratando de hacer.

Tengo una mesa donde cada fila es un cliente y cada columna es un animal que compraron. Llamemos a esta table dataframe.

 > table # P1 P2 P3 # 1 cat lizard parrot # 2 lizard parrot cat # 3 parrot cat lizard 

También tengo una tabla a la que haré referencia llamada lookUp .

 > lookUp # pet class # 1 cat mammal # 2 lizard reptile # 3 parrot bird 

Lo que quiero hacer es crear una nueva tabla llamada new con una función que reemplace todos los valores de la table con la columna de class en lookUp . Intenté esto usando una función de aplicación, pero recibí las siguientes advertencias.

 new  1 and only the first element will be used 2: In gsub(".*", lookUp[match(x, lookUp$pet), 2], x) : argument 'replacement' has length > 1 and only the first element will be used 3: In gsub(".*", lookUp[match(x, lookUp$pet), 2], x) : argument 'replacement' has length > 1 and only the first element will be used 

¿Alguna idea de cómo hacer que esto funcione?

Publicaste un enfoque en tu pregunta que no estaba mal. Aquí hay un enfoque simpático:

 new < - df # create a copy of df # using lapply, loop over columns and match values to the look up table. store in "new". new[] <- lapply(df, function(x) look$class[match(x, look$pet)]) 

Un enfoque alternativo que será más rápido es:

 new < - df new[] <- look$class[match(unlist(df), look$pet)] 

Tenga en cuenta que utilizo corchetes vacíos ( [] ) en ambos casos para mantener la estructura del new como estaba (un data.frame).

(Estoy usando df lugar de table y look lugar de lookup en mi respuesta)

Otra opción es una combinación de tidyr y dplyr

 library(dplyr) library(tidyr) table %>% gather(key = "pet") %>% left_join(lookup, by = "pet") %>% spread(key = pet, value = class) 

Cada vez que tiene dos data.frame separados y está tratando de traer información de uno a otro, la respuesta es fusionarse .

Todos tienen su propio método de fusión favorito en R. Mine es data.table .

Además, dado que desea hacer esto en muchas columnas, será más rápido melt y dcast , en lugar de pasar por encima de las columnas, aplicarlo una vez a una tabla reformada y luego volver a formarse.

 library(data.table) #the row names will be our ID variable for melting setDT(table, keep.rownames = TRUE) setDT(lookUp) #now melt, merge, recast dcast(melt(table, id.vars = "rn" #melting (reshape wide to long) )[lookup, new_value := i.class, on = c(value = "pet")], #merging rn ~ variable, value.var = "new_value") #reform back to original shape # rn P1 P2 P3 # 1: 1 mammal reptile bird # 2: 2 reptile bird mammal # 3: 3 bird mammal reptile 

En caso de que encuentre que el dcast / melt un poco intimidante, aquí hay un enfoque que simplemente pasa por encima de las columnas; dcast / melt simplemente está dcast lado el ciclo para este problema.

 setDT(table) #don't need row names this time setDT(lookUp) sapply(names(table), #(or to whichever are the relevant columns) function(cc) table[lookUp, (cc) := #merge, replace #need to pass a _named_ vector to 'on', so use setNames i.class, on = setNames("pet", cc)]) 

Haz un vector con nombre y recorre cada columna y coincidencia, mira:

 # make lookup vector with names lookUp1 < - setNames(as.character(lookUp$class), lookUp$pet) lookUp1 # cat lizard parrot # "mammal" "reptile" "bird" # match on names get values from lookup vector res <- data.frame(lapply(df1, function(i) lookUp1[i])) # reset rownames rownames(res) <- NULL # res # P1 P2 P3 # 1 mammal reptile bird # 2 reptile bird mammal # 3 bird mammal reptile 

datos

 df1 < - read.table(text = " P1 P2 P3 1 cat lizard parrot 2 lizard parrot cat 3 parrot cat lizard", header = TRUE) lookUp <- read.table(text = " pet class 1 cat mammal 2 lizard reptile 3 parrot bird", header = TRUE) 

La respuesta anterior que muestra cómo hacer esto en dplyr no responde a la pregunta, la tabla está llena de NA. Esto funcionó, agradecería cualquier comentario que muestre una mejor manera:

 # Add a customer column so that we can put things back in the right order table$customer = seq(nrow(table)) classTable < - table %>% # put in long format, naming column filled with P1, P2, P3 "petCount" gather(key="petCount", value="pet", -customer) %>% # add a new column based on the pet's class in data frame "lookup" left_join(lookup, by="pet") %>% # since you wanted to replace the values in "table" with their # "class", remove the pet column select(-pet) %>% # put data back into wide format spread(key="petCount", value="class") 

Tenga en cuenta que probablemente sea útil mantener la tabla larga que contiene al cliente, la mascota, la especie de la mascota (?) Y su clase. Este ejemplo simplemente agrega un guardado intermedio a una variable:

 table$customer = seq(nrow(table)) petClasses < - table %>% gather(key="petCount", value="pet", -customer) %>% left_join(lookup, by="pet") custPetClasses < - petClasses %>% select(-pet) %>% spread(key="petCount", value="class")