2012-11-27 10 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の最終レコード以降の日数」を計算する列。これを行うためのより高速な方法はあり

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] 
} 


今私はこのようになりますFORループを使用していますか?(私は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の答えのように、ここで適用されます。

関連する問題