2011-05-24 7 views
11

Tengo dos tramas de datos:de combinación condicional/reemplazo en I

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 gl1 $ x2 con valores en gl2 $ x2 sobre la base de el partido condicional entre gl1 $ x1 y x2 gl2 $ para producir:

df1 
x1 x2 
1 a 
2 zz 
3 qq 
4 d 

Respuesta

11

uso match(), asumiendo los valores de 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, utilizar:

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

Agradable. Escribí el partido con argumentos invertidos y no pude entender por qué fue más complicado de lo que pensé que debería ser. Añadiré mi respuesta también porque puede ayudar a otros a pensar cómo cambiar el orden de los argumentos en un partido puede hacer que las cosas sean más fáciles o más difíciles. – Aaron

+0

Gracias Joris. Estaba trabajando con 'coincidencia' pero no pude hacerlo funcionar. – Mike

+0

He agregado una solución que funcionará mejor en el caso de valores no exclusivos en df1. – C8H10N4O2

1

usted puede hacerlo haciendo coincidir en el otro sentido, 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 
4

Veo que Joris y Aaron han elegido crear ejemplos sin ningún factor. 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 evite esa restricción y que también permite la posibilidad de que puede haber índices en gl2 que no están en DF1 que creo que invalidaría Joris Meys pero no Aarons soluciones publicado hasta ahora:

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

Se requiere que los niveles ampliarse para incluir la intersección de las dos variables de factor y luego también la necesidad de la gota no coincidentes columnas (= valores NA) en el partido (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 
+1

Agradable. Los factores pueden ser engañosos y el consejo para expandir los niveles es útil. Sin embargo, terminas con un nivel innecesario en 'df1 $ x2' (el' xx'). – Aaron

+0

Si desea eliminar lo que ahora son niveles superfluos, haga lo siguiente: 'df1 $ x2 <- factor (df1 $ x2)' –

4

la primera Parte de la respuesta de Joris es buena, pero en el caso de valores no exclusivos en df1, el bucle for-row no se escalará bien en grandes marcos de datos.

Se podría utilizar una "actualización de unirse a" data.table modificar en su lugar, que será bastante rápido:

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

# (thanks to @Frank for suggestion) 
# Or if you didn't set keys beforehand you could do: 
df1[df2, on = .(x1), x2 := i.x2] 

O, suponiendo que no se preocupan por mantener el orden consecutivo, se puede usar SQL-inspirado dplyr:

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 escala mucho mejor que el ciclo for modo de fila.

+0

La expresión de data.table es 'df1 [df2, on =. (X1), x2: = i.x2] '- se modifica en su lugar (" reemplaza algunos de los valores en df1 $ x2 "como se solicitó OP) y no requiere el establecimiento de claves. Es similar a una unión de actualización de SQL. – Frank

+0

@Frank sí, me pegaste. – C8H10N4O2

+1

Ok. 'df1 [df2, x2: = df2 [, x2]]' no es lo mismo, fyi. – Frank