2017-10-19 137 views
1

我目前正在處理以下數據結構:匹配值

屬性DF:

ID Begin_A  End_A  Interval       Value 
1 5 1990-03-01 2017-03-10 1990-03-01 UTC--2017-03-10 UTC Cat1 
2 10 1993-12-01 2017-12-02 1993-12-01 UTC--2017-12-02 UTC Cat2 
3 5 1991-03-01 2017-03-03 1991-03-01 UTC--2017-03-03 UTC Cat3 
4 10 1995-12-05 2017-12-10 1995-12-05 UTC--2017-12-10 UTC Cat4 

預訂DF:

ID Begin_A  End_A      Interval 
1 5 2017-03-03 2017-03-05 2017-03-03 UTC--2017-03-05 UTC 
2 6 2017-05-03 2017-05-05 2017-05-03 UTC--2017-05-05 UTC 
3 8 2017-03-03 2017-03-05 2017-03-03 UTC--2017-03-05 UTC 
4 10 2017-12-05 2017-12-06 2017-12-05 UTC--2017-12-06 UTC 

正如已經提到的下面的文章:Matching values conditioned on overlapping Intervals and ID,我打算做下面的數據重構:從預訂中取出ID,過濾屬性數據框中的所有行,其中屬性ID m預訂ID。檢查哪些具有匹配屬性ID的行也具有重疊的時間間隔(來自lubridate的int_overlaps)。然後從Value列中取出相應的值,並在Attribute_value列中打印每個值。

預期的結果是這樣的:

ID Begin_A  End_A  Interval      Attribute_value 
5 2017-03-03 2017-03-05 2017-03-03 UTC--2017-03-05 UTC Cat1,Cat3 
6 2017-05-03 2017-05-05 2017-05-03 UTC--2017-05-05 UTC NA 
8 2017-03-03 2017-03-05 2017-03-03 UTC--2017-03-05 UTC NA 
10 2017-12-05 2017-12-06 2017-12-05 UTC--2017-12-06 UTC Cat4 

YCW已經提供了部分答案這個問題在這裏:(https://stackoverflow.com/a/46819541/8259308)。該解決方案不允許的屬性數據幀Begin_A和End_A之間很長時間,因爲有個別日期的矢量與此命令創建:

complete(Date = full_seq(Date, period = 1), ID) %>% 

由於我的原始數據集有很長一段時間了非常大量的觀測屬性數據幀中的幀,R不能處理這些大量的觀測值。我的想法是要麼修改上面提到的行,以減少日期跳躍到幾個月(這也會降低精度)或嘗試新的方法。 下面的代碼產生上文呈現的數據幀:

library(lubridate) 
library(tidyverse) 
# Attributes data frame: 
date1 <- as.Date(c('1990-3-1','1993-12-1','1991-3-1','1995-12-5')) 
date2 <- as.Date(c('2017-3-10','2017-12-2','2017-3-3','2017-12-10')) 
attributes <- data.frame(matrix(NA,nrow=4, ncol = 5)) 
names(attributes) <- c("ID","Begin_A", "End_A", "Interval", "Value") 
attributes$ID <- as.numeric(c(5,10,5,10)) 
attributes$Begin_A <-date1 
attributes$End_A <-date2 
attributes$Interval <-attributes$Begin_A %--% attributes$End_A 
attributes$Value<- as.character(c("Cat1","Cat2","Cat3","Cat4")) 

### Bookings data frame: 

date1 <- as.Date(c('2017-3-3','2017-5-3','2017-3-3','2017-12-5')) 
date2 <- as.Date(c('2017-3-5','2017-5-5','2017-3-5','2017-12-6')) 
bookings <- data.frame(matrix(NA,nrow=4, ncol = 4)) 
names(bookings) <- c("ID","Begin_A", "End_A", "Interval") 
bookings$ID <- as.numeric(c(5,6,8,10)) 
bookings$Begin_A <-date1 
bookings$End_A <-date2 
bookings$Interval <-bookings$Begin_A %--% bookings$End_A 

這是爲了通過YCW提供原來職位的溶液:

library(tidyverse) 

attributes2 <- attributes %>% 
    select(-Interval) %>% 
    gather(Type, Date, ends_with("_A")) %>% 
    select(-Type) %>% 
    group_by(Value) %>% 
    complete(Date = full_seq(Date, period = 1), ID) %>% 
    ungroup() 

bookings2 <- bookings %>% 
    select(-Interval) %>% 
    gather(Type, Date, ends_with("_A")) %>% 
    select(-Type) %>% 
    group_by(ID) %>% 
    complete(Date = full_seq(Date, period = 1)) %>% 
    ungroup() 

bookings3 <- bookings2 %>% 
    left_join(attributes2, by = c("ID", "Date")) %>% 
    group_by(ID) %>% 
    summarise(Attribute_value = toString(sort(unique(Value)))) %>% 
    mutate(Attribute_value = ifelse(Attribute_value %in% "", NA, Attribute_value)) 

bookings4 <- bookings %>% left_join(bookings3, by = "ID") 
bookings4 
    ID Begin_A  End_A      Interval Attribute_value 
1 5 2017-03-03 2017-03-05 2017-03-03 UTC--2017-03-05 UTC  Cat1, Cat3 
2 6 2017-05-03 2017-05-05 2017-05-03 UTC--2017-05-05 UTC   <NA> 
3 8 2017-03-03 2017-03-05 2017-03-03 UTC--2017-03-05 UTC   <NA> 
4 10 2017-12-05 2017-12-06 2017-12-05 UTC--2017-12-06 UTC   Cat4 
+3

退房'data.table :: foverlaps'其是用於執行重疊聯接而設計的。 – Mako212

回答

1

您可以考慮data.table其允許「非相等連接」即基於>=,>,<=<的加入。在相同的調用中,可以對RHS數據集中每行(i)匹配的(L)LHS數據集中的組執行集合操作。

d1[d2, on = .(id = id, end >= begin), 
     .(i.begin, i.end, val_str = toString(val)), by = .EACHI] 

# id  end i.begin  i.end val_str 
# 1: 5 2017-03-03 2017-03-03 2017-03-05 Cat3, Cat1 
# 2: 6 2017-05-03 2017-05-03 2017-05-05   NA 
# 3: 8 2017-03-03 2017-03-03 2017-03-05   NA 
# 4: 10 2017-12-05 2017-12-05 2017-12-06  Cat4 

數據準備:

d1 <- data.frame(id = c(5, 10, 5, 10), 
       begin = as.Date(c('1990-3-1','1993-12-1','1991-3-1','1995-12-5')), 
       end = as.Date(c('2017-3-10','2017-12-2','2017-3-3','2017-12-10')), 
       val = c("Cat1", "Cat2", "Cat3", "Cat4")) 

d2 <- data.frame(id = c(5, 6, 8, 10), 
       begin = as.Date(c('2017-3-3','2017-5-3','2017-3-3','2017-12-5')), 
       end = as.Date(c('2017-3-5','2017-5-5','2017-3-5','2017-12-6'))) 

library(data.table) 
setDT(d1) 
setDT(d2)