Fusión / reemplazo condicional en R

Tengo dos marcos de datos:

df1 x1 x2 1 a 2 b 3 c 4 d 

y

 df2 x1 x2 2 zz 3 qq 

Quiero reemplazar algunos de los valores en df1 $ x2 con valores en df2 $ x2 basados ​​en la coincidencia condicional entre df1 $ x1 y df2 $ x2 para producir:

 df1 x1 x2 1 a 2 zz 3 qq 4 d 

use match() , suponiendo que los valores en df1 son únicos.

 df1 < - data.frame(x1=1:4,x2=letters[1:4],stringsAsFactors=FALSE) df2 <- data.frame(x1=2:3,x2=c("zz","qq"),stringsAsFactors=FALSE) df1$x2[match(df2$x1,df1$x1)] <- df2$x2 > df1 x1 x2 1 1 a 2 2 zz 3 3 qq 4 4 d 

Si los valores no son únicos, use:

 for(id in 1:nrow(df2)){ df1$x2[df1$x1 %in% df2$x1[id]] < - df2$x2[id] } 

Veo que Joris y Aaron han elegido construir ejemplos sin factores. Ciertamente puedo entender esa elección. Para el lector con columnas que ya son factores, también habría una opción de coerción para “personaje”. Hay una estrategia que evita esa restricción y que también permite la posibilidad de que haya índices en df2 que no están en df1, lo que creo que invalidaría a Joris Meys, pero no a las soluciones de Aarons publicadas hasta el momento:

 df1 < - data.frame(x1=1:4,x2=letters[1:4]) df2 <- data.frame(x1=c(2,3,5), x2=c("zz", "qq", "xx") ) 

Requiere que los niveles se expandan para incluir la intersección de ambas variables de factores y luego también la necesidad de colocar columnas no coincidentes (= valores de NA) en concordancia (df1 $ x1, df2 $ x1)

  df1$x2 < - factor(df1$x2 , levels=c(levels(df1$x2), levels(df2$x2)) ) df1$x2[na.omit(match(df2$x1,df1$x1))] <- df2$x2[which(df2$x1 %in% df1$x1)] df1 #----------- x1 x2 1 1 a 2 2 zz 3 3 qq 4 4 d 

La primera parte de la respuesta de Joris es buena, pero en el caso de los valores no exclusivos en df1 , el bucle for-row no se escalará bien en grandes data.frames.

Puede usar una “combinación de actualización” de data.table para modificar en su lugar, lo que será bastante rápido:

 library(data.table) setDT(df1); setDT(df2) df1[df2, on = .(x1), x2 := i.x2] 

O bien, suponiendo que no le importe mantener el orden de las filas, podría usar dplyr SQL:

 library(dplyr) union_all( inner_join( df1["x1"], df2 ), # x1 from df1 with matches in df2, x2 from df2 anti_join( df1, df2["x1"] ) # rows of df1 with no match in df2 ) # %>% arrange(x1) # optional, won't maintain an arbitrary row order 

Cualquiera de estos escalará mucho mejor que el bucle for row-wise.

Puedes hacerlo haciendo coincidir el otro lado también, pero es más complicado. La solución de Joris es mejor, pero lo estoy poniendo aquí también como un recordatorio para pensar de qué manera quieres unir.

 df1 < - data.frame(x1=1:4, x2=letters[1:4], stringsAsFactors=FALSE) df2 <- data.frame(x1=2:3, x2=c("zz", "qq"), stringsAsFactors=FALSE) swap <- df2$x2[match(df1$x1, df2$x1)] ok <- !is.na(swap) df1$x2[ok] <- swap[ok] > df1 x1 x2 1 1 a 2 2 zz 3 3 qq 4 4 d