Rolling Join
데이터테이블의 Rolling-join
데이터 테이블은 dplyr
보다 훨씬 빠를 뿐 아니라, dplyr
에서 지원하지 않는 기능도 가지고 있다. 그 중의 하나가 Rolling-join이다.
Rolling-join은 기준되는 컬럼이 동일하지 않아도 병합되기에 inequality join의 하나이다. 예를 들어 접속 데이터와 구매 데이터를 합치고 싶다고 해보자. 접속 시각과 구매 시각이 완전히 일치할 수는 없다. 구매시간 time_purchase 값이 있을 때, 이보다 이르고, 가장 근접한 접속 시간 time_connect를 연결하고 싶다면 Rolling-join을 쓸 수 있다.
예를 들어 철수는 3월 14일 10시, 3월 15일 11시, 3월 16 14시에 접속을 했고, 3월 15일 13시에 어떤 상품을 구매했다고 해보자.
접속 시간 | 접속 위치 |
---|---|
03/14 10:00 | 222.103.41.37 |
03/15 11:00 | 224.112.52.14 |
03/16 14:00 | 221.103.41.37 |
구매 시간 | 구매 상품 |
---|---|
03/15 13:00 | 스포츠차 |
이 두 테이블은 기존의 방법으로 병합할 수 없다. 왜냐하면 접속 시간과 구매시간이 정확하게 일치하는 열은 없기 때문이다. 반면 통상적으로 접속이 이루어진 후, 구매가 완료되기 때문에 접속과 구매 행위를 연결하기 위해서는 접속 시간은 구매시간보다 이른 시간이며 다른 열과 비교했을 때 가장 가까워야 한다. 이런 경우 Rolling-join을 사용할 수 있다.
형식은 다음과 같다.
DT1[DT2, on=' ', roll= ]
다음은 조금 다른 예이다.
library(data.table)
DTA = data.table(
date = as.Date(c('2018-12-31', '2019-1-4', '2019-1-9')),
duration = c(60, 30, 40))
DTB = data.table(
date = as.Date(c('2018-1-2', '2019-1-5', '2019-1-6')),
product = c('Cosmetics', 'Toys', 'Books'))
date | duration |
---|---|
2018-12-31 | 60 |
2019-01-04 | 30 |
2019-01-09 | 40 |
_ |
---|
date | product |
---|---|
2018-01-02 | Cosmetics |
2019-01-05 | Toys |
2019-01-06 | Books |
DTA
에는 어떤 사람의 온라인 쇼핑몰 접속 기록을 보여준다. 2018년 12월 31일에 60분간 접속했고, 2019년 1월 4일에는 30분간 접속했다(표 10.1).DTB
는 구매 기록을 보여준다. 2018년 1월 2일에는 Cosmetics를 구매했다.
roll = -Inf
여기서 2018년 1월 2일보다 빠르지만 가장 근접한 쇼핑몰 접속 기록을 연결시키고 싶다면? 또는 쇼핑몰 접속 시간과 가장 근접한 이후 구매 시각을 알고 싶다면?
DTB[DTA, on=date, roll=-Inf]
은 DTA
의 date
를 기준으로 DTB
를 연결할 때 만약 일치하는 date
가 없다면 DTB
의 date
를 이전으로 변경시켜서 일치하는 date
를 찾는다. DTB[ , roll=-Inf]
형식임을 주목하자. DTB
의 date
가 하루씩 앞당겨진다. 결과에 date
는 DTA
의 date
이고, DTB
의 date
는 하루씩 앞당겨지면서 병합될 행을 찾는다.
따라서 DTB
의 2018년 1월 2일은 DTA
의 2018년 1월 2일, 1월 1일, 2017년 12월 31일 등과 연결을 시도 한다. 여기서 roll=-Inf
은 동일한 date
을 찾을 때까지 지속됨을 의미한다. 결과는 다음과 같다.
DTB[DTA, on='date', roll=-Inf]
## date product duration ## 1: 2018-12-31 Toys 60 ## 2: 2019-01-04 Toys 30 ## 3: 2019-01-09 <NA> 40
이를 도식적으로 표현하면 다음과 같다.
DTB
의 date
은 DTA
의 date
과 일치할 때 까지 하루씩 과거를 거슬러 올라간다. 그리고 DTA
의 date
과 일치될 때, DTB
와 DTA
의 해당 행이 병합된다. 이때 date
은 DTA
의 date
이다.
만약 구매 시간까지 보존하고자 한다면 다음과 같이 date
를 하나 더 복사해 두면 될 것이다.
DTB[, datePurchase:=date]
DTB[DTA, on='date', roll=-Inf]
## date product datePurchase duration ## 1: 2018-12-31 Toys 2019-01-05 60 ## 2: 2019-01-04 Toys 2019-01-05 30 ## 3: 2019-01-09 <NA> <NA> 40
roll = +3
만약 구매 시간 이후의 가장 근접한 접속 기록을 찾고 싶다면 roll=Inf
을 쓴다.
만약 구매 시간 이후 3일 내의 접속 기록을 찾고 싶다면 roll=3
을 쓴다.
DTB[DTA, on='date', roll=Inf]
## date product datePurchase duration ## 1: 2018-12-31 Cosmetics 2018-01-02 60 ## 2: 2019-01-04 Cosmetics 2018-01-02 30 ## 3: 2019-01-09 Books 2019-01-06 40
DTB[DTA, on='date', roll=3]
## date product datePurchase duration ## 1: 2018-12-31 <NA> <NA> 60 ## 2: 2019-01-04 <NA> <NA> 30 ## 3: 2019-01-09 Books 2019-01-06 40
roll=+3
은 다음과 같이 도식화할 수 있다.
DTB
의 date
을 DTA
의 date
과 일치시키기 위해서 하루씩 늦춰진다. 최대 3일까지. 만약 이렇게 했음에도 DTA
의 date
에 대응하는 DTB
를 찾지 못한다면 DTB
의 열은 모두 NA
가 된다.
정리
여기서는 테이터 테이블의 Rolling-join에 대해 알아보았다. Rolling-join은 주로 날짜를 기준으로 두 데이터테이블을 병합할 때 쓰인다. 특히 roll=
의 의미와 기능을 도식적으로 표현하여 이해를 도왔다.
아쉬운 점
만약 접속 시간과 접속을 유지한 시간이 있다면, 각 행별로 roll=
의 값을 다른 게 설정하면 좋을 것 같다. 하지만 아쉽게도 data.table
에서 roll=
은 하나의 값을 설정해야 한다.
Leave a comment