为了账号安全,请及时绑定邮箱和手机立即绑定

dplyr left_join小于,大于条件

dplyr left_join小于,大于条件

慕桂英3389331 2019-10-21 10:43:46
这个问题在某种程度上与以下问题有关:在非平凡条件下有效地合并两个数据框,并检查r中的日期是否在两个日期之间。我在这里发布的一个请求功能是否存在: GitHub问题我希望使用连接两个数据框dplyr::left_join()。我用来加入的条件是小于,大于,即<=和>。是否dplyr::left_join()支持此功能?或仅在键=之间使用操作符。从SQL运行起来很简单(假设我在数据库中有数据框)这是一个MWE:我有两个数据集,一个企业年(fdata),而第二个是每五年发生一次的调查数据。因此,对于fdata两个调查年度之间的所有年份,我都会加入相应的调查年度数据。id <- c(1,1,1,1,        2,2,2,2,2,2,        3,3,3,3,3,3,        5,5,5,5,        8,8,8,8,        13,13,13)fyear <- c(1998,1999,2000,2001,1998,1999,2000,2001,2002,2003,       1998,1999,2000,2001,2002,2003,1998,1999,2000,2001,       1998,1999,2000,2001,1998,1999,2000)byear <- c(1990,1995,2000,2005)eyear <- c(1995,2000,2005,2010)val <- c(3,1,5,6)sdata <- tbl_df(data.frame(byear, eyear, val))fdata <- tbl_df(data.frame(id, fyear))test1 <- left_join(fdata, sdata, by = c("fyear" >= "byear","fyear" < "eyear"))我懂了Error: cannot join on columns 'TRUE' x 'TRUE': index out of bounds 除非是否left_join可以处理该条件,但是我的语法缺少什么?
查看完整描述

3 回答

?
精慕HU

TA贡献1845条经验 获得超8个赞

使用filter。(但是请注意,此答案不能产生正确的答案LEFT JOIN;但是MWE会给出正确的结果,INNER JOIN而带有a 。)


dplyr如果要求合并两个表而没有要合并的内容,则该程序包不满意,因此在下面,我为此在两个表中都创建了一个哑变量,然后进行过滤,然后删除dummy:


fdata %>% 

    mutate(dummy=TRUE) %>%

    left_join(sdata %>% mutate(dummy=TRUE)) %>%

    filter(fyear >= byear, fyear < eyear) %>%

    select(-dummy)

并注意,如果您在PostgreSQL中进行此操作(例如),查询优化器将通过dummy以下两个查询解释来查看该变量:


> fdata %>% 

+     mutate(dummy=TRUE) %>%

+     left_join(sdata %>% mutate(dummy=TRUE)) %>%

+     filter(fyear >= byear, fyear < eyear) %>%

+     select(-dummy) %>%

+     explain()

Joining by: "dummy"

<SQL>

SELECT "id" AS "id", "fyear" AS "fyear", "byear" AS "byear", "eyear" AS "eyear", "val" AS "val"

FROM (SELECT * FROM (SELECT "id", "fyear", TRUE AS "dummy"

FROM "fdata") AS "zzz136"


LEFT JOIN 


(SELECT "byear", "eyear", "val", TRUE AS "dummy"

FROM "sdata") AS "zzz137"


USING ("dummy")) AS "zzz138"

WHERE "fyear" >= "byear" AND "fyear" < "eyear"



<PLAN>

Nested Loop  (cost=0.00..50886.88 rows=322722 width=40)

  Join Filter: ((fdata.fyear >= sdata.byear) AND (fdata.fyear < sdata.eyear))

  ->  Seq Scan on fdata  (cost=0.00..28.50 rows=1850 width=16)

  ->  Materialize  (cost=0.00..33.55 rows=1570 width=24)

        ->  Seq Scan on sdata  (cost=0.00..25.70 rows=1570 width=24)

并使用SQL更干净地进行操作会得到完全相同的结果:


> tbl(pg, sql("

+     SELECT *

+     FROM fdata 

+     LEFT JOIN sdata 

+     ON fyear >= byear AND fyear < eyear")) %>%

+     explain()

<SQL>

SELECT "id", "fyear", "byear", "eyear", "val"

FROM (

    SELECT *

    FROM fdata 

    LEFT JOIN sdata 

    ON fyear >= byear AND fyear < eyear) AS "zzz140"



<PLAN>

Nested Loop Left Join  (cost=0.00..50886.88 rows=322722 width=40)

  Join Filter: ((fdata.fyear >= sdata.byear) AND (fdata.fyear < sdata.eyear))

  ->  Seq Scan on fdata  (cost=0.00..28.50 rows=1850 width=16)

  ->  Materialize  (cost=0.00..33.55 rows=1570 width=24)

        ->  Seq Scan on sdata  (cost=0.00..25.70 rows=1570 width=24)


查看完整回答
反对 回复 2019-10-21
?
慕桂英4014372

TA贡献1871条经验 获得超13个赞

看起来这是打包Fuzzyjoin地址的任务。软件包的各种功能与dplyr连接功能相似。


在这种情况下,其中一项fuzzy_*_join功能将为您服务。dplyr::left_join和之间的主要区别在于fuzzyjoin::fuzzy_left_join,您提供了在match.fun参数匹配过程中使用的函数列表。请注意,该by参数的写法仍然与相同left_join。


下面是一个例子。我使用的功能来匹配顷>=并<为fyear到byear和fyear到eyear的比较,分别。的


library(fuzzyjoin)


fuzzy_left_join(fdata, sdata, 

             by = c("fyear" = "byear", "fyear" = "eyear"), 

             match_fun = list(`>=`, `<`))


Source: local data frame [27 x 5]


      id fyear byear eyear   val

   (dbl) (dbl) (dbl) (dbl) (dbl)

1      1  1998  1995  2000     1

2      1  1999  1995  2000     1

3      1  2000  2000  2005     5

4      1  2001  2000  2005     5

5      2  1998  1995  2000     1

6      2  1999  1995  2000     1

7      2  2000  2000  2005     5

8      2  2001  2000  2005     5

9      2  2002  2000  2005     5

10     2  2003  2000  2005     5

..   ...   ...   ...   ...   ...


查看完整回答
反对 回复 2019-10-21
  • 3 回答
  • 0 关注
  • 1418 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信