2012-11-27 85 views
5

我有一個數據集,看起來像這樣:計算行之間的差異比for循環更快嗎?

ID | DATE | SCORE 
------------------------- 
123 | 1/15/10 | 10 
123 | 1/1/10 | 15 
124 | 3/5/10 | 20 
124 | 1/5/10 | 30 
... 

所以加載上面的代碼作爲一個數據幀,代碼:

id<-c(123,123,124,124) 
date<-as.Date(c('2010-01-15','2010-01-01','2010-03-05','2010-01-05')) 
score<-c(10,15,20,30) 
data<-data.frame(id,date,score) 


我試圖加列計算「此ID以來的最後一次記錄後的天數」。

現在我使用一個for循環,看起來是這樣的:

data$dayssincelast <- rep(NA, nrow(data)) 
for(i in 2:nrow(data)) { 
    if(data$id[i] == data$id[i-1]) 
    data$dayssincelast[i] <- data$date[i] - data$date[i-1] 
} 


有一個更快的方法來做到這一點?(我已經看了一下APPLY,但不能完全弄清除FOR循環之外的解決方案。)

在此先感謝!

+2

請向你的問題添加'dput(head(data))'的輸出。你的日期看起來不像你可以減去的東西 – GSee

+1

有很多方法可以實現拆分應用,但所有這些方法最終都可能使用'diff'。 – joran

+0

@GSee - 我沒有顯示它,但我已經使用as.Date()轉換了日期。以上只是虛擬數據來說明結構。 –

回答

5

如果您的日期在id以內,那麼這應該有效。

id<-c(123,123,124,124) 
date<-as.Date(c('2010-01-15','2010-01-01','2010-03-05','2010-01-05')) 
score<-c(10,15,20,30) 
data<-data.frame(id,date,score) 

data <- data[order(data$id,data$date),] 
data$dayssincelast<-do.call(c,by(data$date,data$id,function(x) c(NA,diff(x)))) 
# Or, even more concisely 
data$dayssincelast<-unlist(by(data$date,data$id,function(x) c(NA,diff(x)))) 
+0

(我的編輯添加了排序行) –

+0

(沒變,對不起)。 –

0

以下是如何工作的?

indx <- which(data$id == c(data$id[-1], NA)) 
data$date[indx] - data$date[indx+1] 



這只是1轉移的id的,並將它們與ID檢查鄰國匹配。
然後,對於數據減法,只需從後續行的日期中減去匹配即可。

0

在你需要一個更復雜的公式的情況下,你可以使用集合:

a <- aggregate(date ~ id, data=data, FUN=function(x) c(NA,diff(x))) 
data$dayssincelast <- c(t(a[-1]), recursive=TRUE) # Remove 'id' column 

相同的排序順序適用於這裏作爲@nograpes回答。