R中的条件合并/replace
我有两个dataframe:
df1 x1 x2 1 a 2 b 3 c 4 d
和
df2 x1 x2 2 zz 3 qq
我想根据df1 $ x1和df2 $ x2之间的条件匹配,用df2 $ x2中的值replacedf1 $ x2中的一些值,以产生:
df1 x1 x2 1 a 2 zz 3 qq 4 d
使用match()
,假设df1中的值是唯一的。
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
如果这些值不唯一,请使用:
for(id in 1:nrow(df2)){ df1$x2[df1$x1 %in% df2$x1[id]] <- df2$x2[id] }
我看到约里斯和亚伦都select了没有因素的例子。 我当然可以明白这个select。 对于列已经是因素的读者来说,也可以select强制“人物”。 有一个策略可以避免这个限制,也可以允许df2中可能存在不属于df1的索引,我相信这会使Joris Meys失效,但是迄今为止并没有发布Aarons解决scheme:
df1 <- data.frame(x1=1:4,x2=letters[1:4]) df2 <- data.frame(x1=c(2,3,5), x2=c("zz", "qq", "xx") )
它需要扩展水平以包括两个因子variables的交集,然后还需要在匹配(df1 $ x1,df2 $ x1)中删除不匹配的列(= NA值)
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
Joris的答案的第一部分是好的,但在df1
的非唯一值的情况下,在大数据框架中,按行的for循环不能很好地扩展。
你可以使用一个data.table
“更新连接”进行修改,这将是相当快的:
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]
或者,假设您不关心维护行顺序,您可以使用SQL启发的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
这两者中的任何一个都可以比行向for循环好得多。
你可以通过匹配另一种方式来做到这一点,但它更复杂。 Joris的解决scheme比较好,但是我在这里也提醒你考虑一下你想搭配哪种方式。
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