2017-03-14 10 views
0

1つのデータセットでは、アカウント番号(すべて一意)とアカウントで何らかのイベントが発生した日付があります。グループ内で、日付が複数のグループにまたがる正確な間隔を見つける

別のデータセットでは、口座番号と口座ステータスインジケータがあり、口座がそのステータスレベルを入力して終了した日付とともに表示されます。ステータスはステータスが異なるステータスから移動した履歴を生成するため、複数のアカウントが一覧表示されます。

私は、イベントが発生した日にアカウントがあったステータスを最初のデータセットに追加したいと考えています。

私はこのタスクを実行するループを構築しましたが、私が作業しているアカウントの数、履歴の長さ、ステータス "スイッチ"の数を仮定すると、ループは私のシステムでは数時間かかります。

2つのファイルのアカウント番号が同じであるため、data.tableパッケージを使用してアカウント番号にsetkey機能を使用し、data.tableアプローチを使用して追加を高速化する方法があるのだろうと思いましたプロセス。基本的に各アカウント内で、最初のデータセットの日付が2番目のデータセットの日付がどのインターバルになっているかを確認する必要があります。

私は自分のループのためにいくつかのおもちゃのデータと共に作成したコードです。私はlubridateパッケージで間隔を使用しようとしましたが、これは私がbetween()コマンドを使ったので、ループ内のdata.tableにいくつかの問題を与えていました。

誰かが、より効率的な追加プロセスについて考えていますか?ここで

library(data.table) 
library(lubridate) 

set.seed(65) 
# data set 1 
dt1 <- data.table(account=c(1234,1235,1236,1237,1238), 
      eventDate=c(ymd(20170123),ymd(20170223),ymd(20170114),ymd(20170205),ymd(20170127))) 
setkey(dt1,account) 

# data set 2 
se1 <- seq(from=ymd(20161201),to=ymd(20170228), length.out=4) 
se2 <- seq(from=ymd(20170101),to=ymd(20170228), length.out=5) 
se3 <- seq(from=ymd(20170103),to=ymd(20170228), length.out=4) 
se4 <- seq(from=ymd(20160101),to=ymd(20170228), length.out=3) 
se5 <- seq(from=ymd(20161101),to=ymd(20170228), length.out=6) 
ss1 <- c(se1[1]-days(23),se1[-length(se1)]+days(1)) 
ss2 <- c(se2[1]-days(13),se2[-length(se2)]+days(1)) 
ss3 <- c(se3[1]-days(3),se3[-length(se3)]+days(1)) 
ss4 <- c(se4[1]-days(53),se4[-length(se4)]+days(1)) 
ss5 <- c(se5[1]-days(2),se5[-length(se5)]+days(1)) 

dt2 <- data.table(account=c(rep(1234,4),rep(1235,5),rep(1236,4),rep(1237,3),rep(1238,6)), 
      status=sample(LETTERS,22, replace=T), 
      statusStart=c(ss1,ss2,ss3,ss4,ss5), 
      statusEnd=c(se1,se2,se3,se4,se5)) 

setkey(dt2,account) 

#dt2[,interv:=interval(statusStart,statusEnd)] 

# set up and do the loop  
accnts <- dt1[,unique(account)] 

for(i in 1:length(accnts)){ 
    dt2[ account==accnts[i] & 
     between(dt1[account==accnts[i],eventDate],statusStart,statusEnd,incbounds=T), 
     eventDate:=dt1[account==accnts[i],eventDate]] 
} 

# put it back in the first data set 
dt1 <- merge(dt1,dt2[!is.na(eventDate),list(account,eventDate,status)], by=c('account','eventDate'),all.x=T) 

答えて

1

がdata.tableからfoverlaps機能を使用して、それを行うための一つの方法です:

dt1$statusStart <- dt1$eventDate 
dt1$statusEnd <- dt1$eventDate 
setkey(dt2, account, statusStart, statusEnd) 
foverlaps(dt1, dt2, by.x = c('account', 'statusStart', 'statusEnd'), by.y = c('account', 'statusStart', 'statusEnd'), type = 'within') 
+0

うわー! Oropendolaこれは現象的です!私はちょうどdt1が約30Kの行を持ち、dt2が約350Kの行を持つトリミングされたデータセットコンボでこれを実行しました。私のループはおよそ7分かかった。 foverlaps()関数はそれを完了しました。これは準備ができていますか? 0.36秒。このソリューションを提供していただきありがとうございます。非常に効率的です。とても早い。 –

関連する問題