Help us understand the problem. What is going on with this article?

{fuzzyjoin}で等号以外の条件をつけて結合(R編)

はじめに

Rの{dplyr}パッケージの*_join()は、不等号を使って結合することができない。SQLで書けばいいんだけど、Rで不等号を使って結合したい。確かに不等号を使わなくても、解決する方法はあるのですが、不等号を使えたら便利という場面は個人的には多い。そんなときこそ、{fuzzyjoin}パッケージです。ここでは複数の不等号を使った方法を備忘録として記録します。

{fuzzyjoin}パッケージはその他にも便利な使い方があります。他の使い方についえは、下記の記事を参照ください。

不等号を使った結合

例えば、ある一定の期間でアクションを起こしたidだけ引っ張りたい場合を想定します。ad_dfは広告の配信データで、tran_dfは購買履歴だとします。配信日から計測対象期間内でアクションをとった顧客を引っ張りたい。

R
library(tidyverse)
ad_df <- tibble(ad_id = c(paste0("X00",1:9)),
                ad_dt = lubridate::ymd("2018-03-01")) %>% 
  mutate(end_dt = (ad_dt + lubridate::days(3)))

tran_df <- tibble(id = c(paste0("X00",1:5)),
                  order_dt = lubridate::ymd(c("2018-02-28", "2018-03-01", "2018-03-02",
                                              "2018-03-05", "2018-03-06")),
                  total = seq(1000, 5000, 1000))

ad_df
# A tibble: 10 x 3
   ad_id ad_dt      end_dt    
   <chr> <date>     <date>    
 1 X001  2018-03-01 2018-03-04
 2 X002  2018-03-01 2018-03-04
 3 X003  2018-03-01 2018-03-04
 4 X004  2018-03-01 2018-03-04
 5 X005  2018-03-01 2018-03-04
 6 X006  2018-03-01 2018-03-04
 7 X007  2018-03-01 2018-03-04
 8 X008  2018-03-01 2018-03-04
 9 X009  2018-03-01 2018-03-04
10 X0010 2018-03-01 2018-03-04

tran_df
# A tibble: 5 x 3
  id    order_dt   total
  <chr> <date>     <dbl>
1 X001  2018-02-28  1000
2 X002  2018-03-01  2000
3 X003  2018-03-02  3000
4 X004  2018-03-05  4000
5 X005  2018-03-06  5000

こんなときに{fuzzyjoin}パッケージは便利です。fuzzy_left_join(x, y, by, match_fun)で条件を記述します。まずは左外部結合をやってみます。match_funで統合を指定する場合は=ではなく==なので注意。

R
is_order_df <- fuzzy_left_join(ad_df, tran_df, 
                               by = c("ad_id" = "id", "ad_dt" = "order_dt", "end_dt" = "order_dt"), 
                               match_fun = list(`==`, `<=`, `>=`))

is_order_df
# A tibble: 10 x 6
   ad_id ad_dt      end_dt     id    order_dt   total
   <chr> <date>     <date>     <chr> <date>     <dbl>
 1 X001  2018-03-01 2018-03-04 NA    NA            NA
 2 X002  2018-03-01 2018-03-04 X002  2018-03-01  2000
 3 X003  2018-03-01 2018-03-04 X003  2018-03-02  3000
 4 X004  2018-03-01 2018-03-04 NA    NA            NA
 5 X005  2018-03-01 2018-03-04 NA    NA            NA
 6 X006  2018-03-01 2018-03-04 NA    NA            NA
 7 X007  2018-03-01 2018-03-04 NA    NA            NA
 8 X008  2018-03-01 2018-03-04 NA    NA            NA
 9 X009  2018-03-01 2018-03-04 NA    NA            NA
10 X0010 2018-03-01 2018-03-04 NA    NA            NA

問題なく、期間内にアクションを起こしたidをひけています。今回のような場合は内部結合でも問題ないので、fuzzy_inner_join()も試します。

R
fuzzy_inner_join(ad_df, tran_df,
                 by = c("ad_id" = "id", "ad_dt" = "order_dt", "end_dt" = "order_dt"), 
                 match_fun = list(`==`, `<=`, `>=`))
# A tibble: 2 x 6
 ad_id  ad_dt      end_dt     id     order_dt   total
 <chr>  <date>     <date>     <chr>  <date>     <dbl>
1 X002  2018-03-01 2018-03-04 X002  2018-03-01  2000
2 X003  2018-03-01 2018-03-04 X003  2018-03-02  3000

あとは好きに加工して、やりたいことやる。{fuzzyjoin}パッケージ、大変便利なパッケージですね。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away