我想根据一个联合列和行的条件选择性地左联接两个数据帧。
我看到了一些使用fuzzyjoin和sqldf的类似帖子,但我发现之前的例子与我的不完全一样。
示例dfs:
df1 <- data.frame(id = c("1", "2", "3"),
zipcode = c("11111", "44444", "33333"),
exp.id = c("0", "0", "1"))
df2 <- data_frame(zipcode = c("11111", "22222", "33333", "44444", "55555"),
pct = c("0.1", "0.5", "0.9", "0.7", "0.8"))
基本上,我想加入";pct";列通过邮政编码从df2到df1,但仅在"处连接;exp.id"="0";
我期望的结果应该是这样的:
id zipcode exp.id pct
<chr> <chr> <chr> <chr>
1 1 11111 0 0.1
2 2 44444 0 0.7
3 3 33333 1 NA
提前谢谢。
1(此左键将df1
与zipcode
上的df2
连接,但仅连接exp.id
为0的行。对于其他行,pct
是NA,如问题中所示的预期结果。请注意,dot是一个SQL运算符,因此我们用方括号将exp.id
括起来以转义名称。
library(sqldf)
sqldf("select a.id, a.zipcode, b.pct
from df1 a
left join df2 b on a.zipcode = b.zipcode and [exp.id] = 0")
## id zipcode pct
## 1 1 11111 0.1
## 2 2 44444 0.7
## 3 3 33333 <NA>
2(这与(1(类似,但只返回零的exp.id
行。这与问题中的要求不同,但一条评论表明这很有意思。
这里的代码和(1(之间的差异说明了在on
和where
中包括条件之间的细微差异。因为在这种情况下我们有一个简单的条件,所以我们可以使用using
子句而不是on
。using
产生单个zipcode
,因此我们不需要区分a.zipcode
和b.zipcode
。
sqldf("select a.id, zipcode, b.pct
from df1 a left join df2 b using(zipcode)
where [exp.id] = 0")
## id zipcode pct
## 1 1 11111 0.1
## 2 2 44444 0.7
请注意,SQL引擎在内部创建一个查询计划,以优化计算,同时保持相同的输出。它不一定按写入的顺序执行操作,也就是说,它不一定执行联接然后减少结果,但可以首先减少df1以提高性能,因为这会产生相同的结果。我们在下面显示了查询计划的信息,我们看到,实际上,它首先扫描df1
。
sqldf("explain query plan select a.id, zipcode, b.pct
from df1 a left join df2 b using(zipcode)
where [exp.id] = 0")
## id parent notused detail
## 1 3 0 0 SCAN TABLE df1 AS a
## 2 16 0 0 SEARCH TABLE df2 AS b USING AUTOMATIC COVERING INDEX (zipcode=?)
连接数据并将pct
值转换为NA
,其中exp.id != 0
。
library(dplyr)
res <- df1 %>%
left_join(df2, by = 'zipcode') %>%
mutate(pct = replace(pct, exp.id != 0, NA))
res
# id zipcode exp.id pct
#1 1 11111 0 0.1
#2 2 44444 0 0.7
#3 3 33333 1 <NA>
在基地R-
res <- transform(merge(df1, df2, by = 'zipcode', all.x = TRUE),
pct = replace(pct, exp.id != 0, NA))
此外,您只能在exp.id = 0
处加入那些值。
df1 %>%
filter(exp.id == 0) %>%
left_join(df2, by = 'zipcode') %>%
right_join(df1)