2014-02-25 90 views
3

也許答案應該很明顯,但我有點卡住了。總計時間間隔R中的日期數據與重疊日期

我的數據看起來是這樣的:

> df <- data.frame(person = c("A", "B", "C"), start = c("2014-01-01", "2014-01-02", "2014-01-03"), stop = c("2014-01-05", "2014-01-06", "2014-01-04")) 
> df 
    person  start  stop 
1  A 2014-01-01 2014-01-05 
2  B 2014-01-02 2014-01-06 
3  C 2014-01-03 2014-01-04 

最後,我想繪製的人在某一天做一個活動的總人數,但會滿足於只是清點每天數(即總清點當開始和結束日期已知時,每個日期的發生次數)。對於上述數據,這就是我要尋找的答案:

 Date Tally 
2014-01-01 1 
2014-01-02 2 
2014-01-03 3 
2014-01-04 3 
2014-01-05 2 
2014-01-06 1 

我有嘗試過的方法是使用SEQ()來生成所有日期,但這似乎並沒有爲開始工作/停止長的日期> 1:

seq(df$start, df$stop, length = "1 day") ## Does not work 

任何幫助將不勝感激。

回答

3

客場可能是:

as.data.frame(table(unlist(apply(df[-1], 1, 
     function(x) as.character(seq(as.Date(x[1], "%Y-%m-%d"), 
            as.Date(x[2], "%Y-%m-%d"), "1 day")))))) 
     Var1 Freq 
1 2014-01-01 1 
2 2014-01-02 2 
3 2014-01-03 3 
4 2014-01-04 3 
5 2014-01-05 2 
6 2014-01-06 1 

既然你正在尋找的效率,同樣的答案可能避免一些瓶頸有待加快。首先,請注意循環中每次調用as.Date。這是因爲在循環之前調用它一次將不會產生任何效果,因爲apply強制轉換爲矩陣,因此日期被強制轉換爲字符,因此seq將產生錯誤。其次,你可以避免使用seq的方法來處理類「Date」的開銷。第三,你需要幾天的時間。這些都令人鼓舞,將日期轉換爲整數並在類「數字」上運行。

f1 = function() { #keeping dates 
    as.data.frame(table(unlist(apply(df[-1], 1, 
     function(x) as.character(seq(as.Date(x[1], "%Y-%m-%d"), 
            as.Date(x[2], "%Y-%m-%d"), "1 day")))))) 
}          
f2 = function() { #using numeric 
    df$start = as.numeric(as.Date(df$start, "%Y-%m-%d")) 
    df$stop = as.numeric(as.Date(df$stop, "%Y-%m-%d")) 
    res = as.data.frame(table(unlist(apply(df[-1], 1, 
         function(x) seq(x[1], x[2]))))) 
    res$Var1 = factor(as.Date(as.numeric(as.character(res$Var1)), 
          origin = "1970-01-01")) 
    res      
} 
f1() 
#  Var1 Freq 
#1 2014-01-01 1 
#2 2014-01-02 2 
#3 2014-01-03 3 
#4 2014-01-04 3 
#5 2014-01-05 2 
#6 2014-01-06 1 
f2() 
#  Var1 Freq 
#1 2014-01-01 1 
#2 2014-01-02 2 
#3 2014-01-03 3 
#4 2014-01-04 3 
#5 2014-01-05 2 
#6 2014-01-06 1 

和基準在更大data.frame:

df = data.frame(person = paste("ID", 1:1e3, sep = ""), 
       start = as.Date(sample(Sys.Date() : (Sys.Date()+10), 1e3, T), 
           origin = "1970-01-01")) 
df$stop = df$start + 5 
head(df) 
# person  start  stop 
#1 ID1 2014-03-07 2014-03-12 
#2 ID2 2014-03-01 2014-03-06 
#3 ID3 2014-03-04 2014-03-09 
#4 ID4 2014-02-28 2014-03-05 
#5 ID5 2014-02-27 2014-03-04 
#6 ID6 2014-03-07 2014-03-12 
identical(f1(), f2()) 
#[1] TRUE 
library(microbenchmark) 
microbenchmark(f1(), f2(), times = 10) 
#Unit: milliseconds 
# expr  min  lq median  uq  max neval 
# f1() 366.90895 368.36777 379.78573 395.82724 410.17782 10 
# f2() 31.66473 32.11122 33.04891 33.62642 35.75063 10 
+0

謝謝,這工作得很好,是比較快的。 – BeginR

+0

@BeginR看看是否有助於我對你的評論做出的一些修改 –

+0

謝謝,甚至更好。 – BeginR

2

這工作:

df[, -1] <- lapply(df[-1], as.Date) 

data.frame(table(unlist(lapply(1:nrow(df), function(i) { 
    as.character(seq.Date(df$start[i], df$stop[i], "day")) 
})))) 

##   Var1 Freq 
## 1 2014-01-01 1 
## 2 2014-01-02 2 
## 3 2014-01-03 3 
## 4 2014-01-04 3 
## 5 2014-01-05 2 
## 6 2014-01-06 1 
+0

這也適用,但在較大的數據集上使用時需要很長時間才能計算。 – BeginR