2016-07-23 51 views
1

我有兩個數據框x和y,它們包含ids和日期的列。按ID和重疊日期範圍加入數據框

id.x <- c(1, 2, 4, 5, 7, 8, 10) 
date.x <- as.Date(c("2015-01-01", "2015-01-02", "2015-01-21", "2015-01-13", "2015-01-29", "2015-01-01", "2015-01-03"),format = "%Y-%m-%d") 
x <- data.frame(id.x, date.x) 
id.y <- c(1, 2, 3, 6, 7, 8, 9) 
date.y <- as.Date(c("2015-01-03", "2015-01-29", "2015-01-22", "2015-01-13", "2015-01-29", "2014-12-31", "2015-01-03"), format = "%Y-%m-%d") 
y <- data.frame(id.y, date.y) 

我想通過匹配ID和閹date.y將它們加入到一個新的數據幀Z的內側date.x + 3天,例如發生在date.y =「2015-01-03」上發生事件「y」,事件x在date.x =「2015-01-01」的3天內發生了事件「y」。

+0

請停止使用'cbind'來創建data.frames ..有一個data.frame函數可用於此。 – Arun

+0

@阿倫注意。如果其他人對cbind.data.frame()和data.frame()之間的區別感到好奇,可以很好地總結[here](https://docs.tibco.com/pub/enterprise-runtime- for-R/1.5.0_may_2013/TERR_1.5.0_LanguageRef/base/cbind.data.frame.html) – user6571411

+0

在調用data.frame()時使用'check.names = FALSE'(以獲得' cbind.data.frame'),這似乎是唯一的默認差異。 – Arun

回答

1

您可以創建一個ifelse語句,創建一個等於date.x的向量,如果date.y < = date.x + 3和date.y> = date.x,否則等於date.y。然後合併在此基礎上向量兩種:

id.x <- c(1, 2, 4, 5, 7, 8, 10) 
date.x <- as.Date(c("2015-01-01", "2015-01-02", "2015-01-21", "2015-01-13", "2015-01-29", "2015-01-01", "2015-01-03"),format = "%Y-%m-%d") 
x <- cbind.data.frame(id.x, date.x) 
id.y <- c(1, 2, 3, 6, 7, 8, 9) 
date.y <- as.Date(c("2015-01-03", "2015-01-29", "2015-01-22", "2015-01-13", "2015-01-29", "2014-12-31", "2015-01-03"), format = "%Y-%m-%d") 
y <- cbind.data.frame(id.y, date.y) 

safe.ifelse <- function(cond, yes, no) structure(ifelse(cond, yes, no), class = class(yes)) 

match <- safe.ifelse(date.y <= date.x+3 & date.y >= date.x, 
      match <- date.x, 
      match <- date.y) 

y$date.x <- match 
names(y)[1] <- "id.x" 

dplyr::left_join(x, y, by=c("id.x","date.x")) 

    id.x  date.x  date.y 
1 1 2015-01-01 2015-01-03 
2 2 2015-01-02  <NA> 
3 4 2015-01-21  <NA> 
4 5 2015-01-13  <NA> 
5 7 2015-01-29 2015-01-29 
6 8 2015-01-01  <NA> 
7 10 2015-01-03  <NA> 

我從這個postsafe.ifelse功能,因爲該基地ifelse語句會導致一個數字矢量,而不是最新矢量。

+0

這是不安全的,通常會導致錯誤的解決方案。你們這一代的'match'專欄根本不考慮'id'專欄。 – Arun

+0

我遇到了Arun提到的問題。我的工作如下 'temp < - merge(x,y,by.x =「id.x」,by.y =「id.y」,all = TRUE)' 'temp.subset < - safe.ifelse(date.y <= date.x + 3&date.y> = date.x,TRUE,FALSE)' 'joined.df < - temp [which(temp.subset == TRUE),] ' – user6571411

1

通過將鍵設置爲兩個數據表的ID,然後檢查日期條件,最後提取真正的數據表,使用y和x數據表的內部連接。

library("data.table") 

x <- as.data.table(x) 

y <- as.data.table(y) 

setkey(x, id.x) 

setkey(y, id.y) 

z <- y[x, nomatch = 0][, j = .(is_true = ((date.y <= date.x + 3) & (date.y > date.x)), id.y, date.x, date.y)][i = is_true == TRUE] 

> z 
    is_true id.y  date.x  date.y 
1: TRUE 1 2015-01-01 2015-01-03 
1

使用data.table,v1.9.7,其中非球菌(或條件)聯接最近實施的,我們可以在一個簡單的(和效率)的方式做到這一點的開發版本。請參見安裝說明here

require(data.table) # v1.9.7+ 
setDT(x) 
setDT(y) ## convert both data.frames to data.tables by reference 

x[, date.x.plus3 := date.x + 3L] 
y[x, .(id.x, date.x, date.y=x.date.y), 
    on=.(id.y == id.x, date.y >= date.x, date.y <= date.x.plus3)] 
# id.x  date.x  date.y 
# 1: 1 2015-01-01 2015-01-03 
# 2: 2 2015-01-02  <NA> 
# 3: 4 2015-01-21  <NA> 
# 4: 5 2015-01-13  <NA> 
# 5: 7 2015-01-29 2015-01-29 
# 6: 8 2015-01-01  <NA> 
# 7: 10 2015-01-03  <NA> 

解決方案,加入上一虛設列,然後篩選基於所述條件通常不可擴展(如行數迅速爆炸),並通過行的解決方案,循環和運行的每一行被過濾條件很慢,因爲他們按行進行操作。

該解決方案既不執行,也就是直接執行條件連接,因此應該在運行時和內存兩方面都是高性能的。