选择性左加入 r

Selective left join in r

我想根据联合列和行的条件有选择地左连接两个数据框。

我看到一些类似的帖子使用 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"))

基本上,我想通过邮政编码将 df2 中的“pct”列加入到 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  

提前致谢。

加入数据并将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)

1) 这左连接 df1zipcode 上的 df2 但仅连接 exp.id 为 0 的行. 对于其他行 pct 是 NA,如问题中所示的预期结果。请注意,点是一个 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),但 returns 只有 exp.id 行为零。这与问题中要求的不同,但评论表明它很有趣。

这里的代码和 (1) 之间的区别说明了在 onwhere 中包含条件之间的细微差别。因为在这种情况下我们有一个简单的条件,所以我们可以使用 using 子句而不是 onusing 结果是一个 zipcode 所以我们不需要区分 a.zipcodeb.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=?)