我有两个数据框:
df1
x1 x2
1 a
2 b
3 c
4 d
和
df2
x1 x2
2 zz
3 qq
我想根据df1 $ x1和df2 $ x2之间的条件匹配,用df2 $ x2中的值替换df1 $ x2中的某些值,以产生:
df1
x1 x2
1 a
2 zz
3 qq
4 d
答案 0 :(得分:16)
使用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]
}
答案 1 :(得分:4)
我看到Joris和Aaron都选择在没有因素的情况下构建示例。我当然可以理解这个选择。对于具有已经是因素的列的读者,也可以选择强制为“字符”。有一种策略可以避免这种限制,并且还允许df2中可能存在不在df1中的索引的可能性,我认为这将使Joris Meys无效,但到目前为止没有发布Aarons解决方案:
df1 <- data.frame(x1=1:4,x2=letters[1:4])
df2 <- data.frame(x1=c(2,3,5), x2=c("zz", "qq", "xx") )
它要求扩展级别以包含两个因子变量的交集,然后还需要在匹配中删除不匹配的列(= NA值)(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
答案 2 :(得分:4)
Joris的第一部分&#39;答案是好的,但在df1
中非唯一值的情况下,行式for循环在大型data.frames上不能很好地扩展。
您可以使用data.table
&#34;更新加入&#34;修改到位,这将非常快:
library(data.table)
setDT(df1); setDT(df2)
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-loop更好地扩展。
答案 3 :(得分:2)
我们可以使用我的软件包safejoin中的eat
,并进行“补丁”
列冲突时,从rhs到lhs的匹配。
# devtools::install_github("moodymudskipper/safejoin")
library(safejoin)
library(dplyr)
df1 <- data.frame(x1=1:4,x2=letters[1:4],stringsAsFactors=FALSE)
df2 <- data.frame(x1=2:3,x2=c("zz","qq"),stringsAsFactors=FALSE)
eat(df1, df2, .by = "x1", .conflict = "patch")
# x1 x2
# 1 1 a
# 2 2 zz
# 3 3 qq
# 4 4 d
答案 4 :(得分:1)
你可以通过匹配其他方式来实现它,但它更复杂。 Joris的解决方案更好,但我也把它放在这里作为一个提醒,思考你想要匹配的方式。
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
答案 5 :(得分:0)
是这里的新功能,但使用以下dplyr方法似乎也可以工作
与上述答案之一相似但略有不同
df3 <- anti_join(df1, df2, by = "x1")
df3 <- rbind(df3, df2)
df3
答案 6 :(得分:0)
可以通过dplyr
完成。
library(dplyr)
full_join(df1,df2,by = c("x1" = "x1")) %>%
transmute(x1 = x1,x2 = coalesce(x2.y,x2.x))
x1 x2
1 1 a
2 2 zz
3 3 qq
4 4 d