2014-02-04 4 views
12

У меня есть две таблицы, policies и claimsТаблица данных слияния на основе даты диапазоны

policies<-data.table(policyNumber=c(123,123,124,125), 
       EFDT=as.Date(c("2012-1-1","2013-1-1","2013-1-1","2013-2-1")), 
       EXDT=as.Date(c("2013-1-1","2014-1-1","2014-1-1","2014-2-1"))) 
> policies 
    policyNumber  EFDT  EXDT 
1:   123 2012-01-01 2013-01-01 
2:   123 2013-01-01 2014-01-01 
3:   124 2013-01-01 2014-01-01 
4:   125 2013-02-01 2014-02-01 


claims<-data.table(claimNumber=c(1,2,3,4), 
        policyNumber=c(123,123,123,124), 
        lossDate=as.Date(c("2012-2-1","2012-8-15","2013-1-1","2013-10-31")), 
        claimAmount=c(10,20,20,15)) 
> claims 
    claimNumber policyNumber lossDate claimAmount 
1:   1   123 2012-02-01   10 
2:   2   123 2012-08-15   20 
3:   3   123 2013-01-01   20 
4:   4   124 2013-10-31   15 

таблица политики действительно содержит директивные термины, поскольку каждая строка однозначно идентифицируется номером политики наряду с эффективной датой.

Я хочу объединить две таблицы таким образом, чтобы связывать претензии с политическими терминами. Требование связано с термином политики, если он имеет тот же номер политики, а убыток - в соответствии с датой вступления в силу и датой истечения срока действия политики (эффективные даты - это включенные ограничения и даты истечения срока действия являются исключительными ограничениями.) Я объединять таблицы таким образом?

Это должно быть похоже на левое внешнее соединение. Результат должен выглядеть так:

policyNumber  EFDT  EXDT claimNumber lossDate claimAmount 
1:   123 2012-01-01 2013-01-01   1 2012-02-01   10 
2:   123 2012-01-01 2013-01-01   2 2012-08-15   20 
3:   123 2013-01-01 2014-01-01   3 2013-01-01   20 
4:   124 2013-01-01 2014-01-01   4 2013-10-31   15 
5:   125 2013-02-01 2014-02-01   NA  <NA>   NA 
+0

возможно дубликат [присоединяемых концов диапазона с последовательностью] (http://stackoverflow.com/questions/17597508/merging-endpoints-of-a-range-with-a- последовательность) – eddi

+1

У меня были проблемы с использованием рулона, когда то, что вы действительно хотите сделать, соответствует диапазону. Если у вас возникли проблемы с получением результатов, вы ожидаете, что один из подходов будет состоять в том, чтобы преобразовать диапазон в уникальную строку для каждого возможного значения. Примером может служить этот вопрос, который, как ни странно, ответил eddi. http://stackoverflow.com/questions/16423817/create-dummy-variables-in-one-table-based-on-range-of-dates-in-another-table –

+0

@DeanMacGregor, который был до того, как я узнал, как использовать 'roll' :) Вы можете увидеть комментарии там для другого сообщения SO, где очень похожая проблема решается с помощью' roll'. – eddi

ответ

7

Версия 1 (обновляется data.table v1.9.4 +)

Попробуйте это:

# Policies table; I've added policyNumber 126: 
policies<-data.table(policyNumber=c(123,123,124,125,126), 
        EFDT=as.Date(c("2012-01-01","2013-01-01","2013-01-01","2013-02-01","2013-02-01")), 
        EXDT=as.Date(c("2013-01-01","2014-01-01","2014-01-01","2014-02-01","2014-02-01"))) 

# Claims table; I've added two claims for 126 that are before and after the policy dates: 
claims<-data.table(claimNumber=c(1,2,3,4,5,6), 
        policyNumber=c(123,123,123,124,126,126), 
        lossDate=as.Date(c("2012-2-1","2012-8-15","2013-1-1","2013-10-31","2012-06-01","2014-03-01")), 
        claimAmount=c(10,20,20,15,5,25)) 

# Set the keys for policies and claims so we can join them: 
setkey(policies,policyNumber,EFDT) 
setkey(claims,policyNumber,lossDate) 

# Join the tables using roll 
# ans<-policies[claims,list(EFDT,EXDT,claimNumber,lossDate,claimAmount,inPolicy=F),roll=T][,EFDT:=NULL] ## This worked with earlier versions of data.table, but broke when they updated the by-without-by behavior... 
ans<-policies[claims,list(.EFDT=EFDT,EXDT,claimNumber,lossDate,claimAmount,inPolicy=F),by=.EACHI,roll=T][,`:=`(EFDT=.EFDT, .EFDT=NULL)] 

# The claim should have inPolicy==T where lossDate is between EFDT and EXDT: 
ans[lossDate>=EFDT & lossDate<=EXDT, inPolicy:=T] 

# Set the keys again, but this time we'll join on both dates: 
setkey(ans,policyNumber,EFDT,EXDT) 
setkey(policies,policyNumber,EFDT,EXDT) 

# Union the ans table with policies that don't have any claims: 
ans<-rbindlist(list(ans, ans[policies][is.na(claimNumber)])) 

ans 
# policyNumber  EFDT  EXDT claimNumber lossDate claimAmount inPolicy 
#1:   123 2012-01-01 2013-01-01   1 2012-02-01   10  TRUE 
#2:   123 2012-01-01 2013-01-01   2 2012-08-15   20  TRUE 
#3:   123 2013-01-01 2014-01-01   3 2013-01-01   20  TRUE 
#4:   124 2013-01-01 2014-01-01   4 2013-10-31   15  TRUE 
#5:   126  <NA>  <NA>   5 2012-06-01   5 FALSE 
#6:   126 2013-02-01 2014-02-01   6 2014-03-01   25 FALSE 
#7:   125 2013-02-01 2014-02-01   NA  <NA>   NA  NA 

Version 2

@Arun предложил использовать новую foverlaps функцию из data.table. Моя попытка ниже кажется сложнее, а не проще, поэтому, пожалуйста, дайте мне знать, как ее улучшить.

## The foverlaps function requires both tables to have a start and end range, and the "y" table to be keyed 
claims[, lossDate2:=lossDate] ## Add a redundant lossDate column to use as the end range for claims 
setkey(policies, policyNumber, EFDT, EXDT) ## Set the key for policies ("y" table) 

## Find the overlaps, remove the redundant lossDate2 column, and add the inPolicy column: 
ans2 <- foverlaps(claims, policies, by.x=c("policyNumber", "lossDate", "lossDate2"))[, `:=`(inPolicy=T, lossDate2=NULL)] 

## Update rows where the claim was out of policy: 
ans2[is.na(EFDT), inPolicy:=F] 

## Remove duplicates (such as policyNumber==123 & claimNumber==3), 
## and add policies with no claims (policyNumber==125): 
setkey(ans2, policyNumber, claimNumber, lossDate, EFDT) ## order the results 
setkey(ans2, policyNumber, claimNumber) ## set the key to identify unique values 
ans2 <- rbindlist(list(
    unique(ans2), ## select only the unique values 
    policies[!.(ans2[, unique(policyNumber)])] ## policies with no claims 
), fill=T) 

ans2 
## policyNumber  EFDT  EXDT claimNumber lossDate claimAmount inPolicy 
## 1:   123 2012-01-01 2013-01-01   1 2012-02-01   10  TRUE 
## 2:   123 2012-01-01 2013-01-01   2 2012-08-15   20  TRUE 
## 3:   123 2012-01-01 2013-01-01   3 2013-01-01   20  TRUE 
## 4:   124 2013-01-01 2014-01-01   4 2013-10-31   15  TRUE 
## 5:   126  <NA>  <NA>   5 2012-06-01   5 FALSE 
## 6:   126  <NA>  <NA>   6 2014-03-01   25 FALSE 
## 7:   125 2013-02-01 2014-02-01   NA  <NA>   NA  NA 

версия 3

Используя foverlaps(), другая версия:

require(data.table) ## 1.9.4+ 
setDT(claims)[, lossDate2 := lossDate] 
setDT(policies)[, EXDTclosed := EXDT-1L] 
setkey(claims, policyNumber, lossDate, lossDate2) 
foverlaps(policies, claims, by.x=c("policyNumber", "EFDT", "EXDTclosed")) 

foverlaps() требует как начать и КОНЕЦ диапазонов/интервалов. Поэтому мы дублируем колонку lossDate на lossDate2.

С EXDT должен быть интервал между интервалами, вычесть его из него и поместить его в новый столбец EXDTclosed.

Теперь мы устанавливаем ключ. foverlaps() требует, чтобы последние два ключевых столбца были интервалами. Поэтому они указаны последним. И мы также хотим, чтобы совпадение было объединено для первого совпадения на policyNumber. Следовательно, это также указано в ключе.

Нам необходимо установить ключ на claims (отметьте ?foverlaps). Нам не нужно устанавливать ключ на policies. Но вы можете, если хотите (тогда вы можете пропустить аргумент by.x, поскольку он по умолчанию принимает значение ключа).Поскольку мы не устанавливаем ключ для policies здесь, мы будем явно указывать соответствующие столбцы в аргументе by.x. Тип перекрытия по умолчанию - any, который нам не нужно менять (и поэтому не указывать). Это приводит к:

# policyNumber claimNumber lossDate claimAmount lossDate2  EFDT  EXDT EXDTclosed 
# 1:   123   1 2012-02-01   10 2012-02-01 2012-01-01 2013-01-01 2012-12-31 
# 2:   123   2 2012-08-15   20 2012-08-15 2012-01-01 2013-01-01 2012-12-31 
# 3:   123   3 2013-01-01   20 2013-01-01 2013-01-01 2014-01-01 2013-12-31 
# 4:   124   4 2013-10-31   15 2013-10-31 2013-01-01 2014-01-01 2013-12-31 
# 5:   125   NA  <NA>   NA  <NA> 2013-02-01 2014-02-01 2014-01-31 
+0

Спасибо за ответ. Это ошибка при первом запуске 'ans'. объект 'EFDT' не найден – Ben

+0

Хм ... Интересно, имеет ли значение версия 'data.table' (я использую 1.8.11)? В качестве обходного пути посмотрите, что произойдет, если вы удалите последний бит ('[, EFDT: = NULL]') из этой строки кода. – dnlbrky

+0

Такая же ошибка, и я использую 1.8.8 – Ben

1

Я думаю, что это в основном то, что вы хотите. Мне нужно работать, так что не было времени, чтобы добавить политику без претензий и очистки колонны, но я думаю, что сложные проблемы решаются:

setkey(policies, policyNumber, EXDT) 
policies[, EXDT2:=EXDT] 
policies[claims[, list(policyNumber, lossDate, lossDate, claimNumber, claimAmount)], roll=-Inf] 
# policyNumber  EXDT  EFDT  EXDT2 lossDate claimNumber claimAmount 
# 1:   123 2012-02-01 2012-01-01 2013-01-01 2012-02-01   1   10 
# 2:   123 2012-08-15 2012-01-01 2013-01-01 2012-08-15   2   20 
# 3:   123 2013-01-01 2012-01-01 2013-01-01 2013-01-01   3   20 
# 4:   124 2013-10-31 2013-01-01 2014-01-01 2013-10-31   4   15 

Кроме того, обратите внимание, что тривиальное удалить претензии/выделить вне даты политики от этого результата.

Смежные вопросы