2012-11-27 13 views
5

ich einen Datensatz haben, die wie folgt aussieht:Unterschiede zwischen Zeilen schneller berechnen als eine for-Schleife?

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

So das obige Snippet als Datenrahmen zu laden, ist der Code:

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) 


Ich versuche, ein hinzufügen Spalte, die die "Tage seit dem letzten Datensatz für diese ID" berechnet.

Im Moment bin ich mit einer FOR-Schleife, die etwa wie folgt aussieht:

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


Gibt es einen schnelleren Weg, dies zu tun? (Ich habe ein wenig in APPLY geschaut, aber kann nicht eine Lösung neben einer FOR-Schleife herausfinden.)

Vielen Dank im Voraus!

+2

Bitte fügen Sie zu Ihrer Frage die Ausgabe von 'dput (Kopf (Daten))'. Ihre Daten sehen nicht wie etwas aus, das Sie subtrahieren können. – GSee

+1

Es gibt viele Möglichkeiten, sich dem Split-Apply-Stück zu nähern, aber alle von ihnen werden wahrscheinlich mit 'diff' enden. – joran

+0

@GSee - Ich habe es nicht angezeigt, aber ich habe die Daten bereits mit asDate() konvertiert. Das obige ist nur Dummy-Daten, um die Struktur zu veranschaulichen. –

Antwort

5

Dies sollte funktionieren, wenn Ihre Daten innerhalb von id in Ordnung sind.

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

(Meine Änderung hinzugefügt die Bestellzeile) –

+0

(Keine Änderung. Tut mir leid.) –

0

Wie funktioniert das Folgende für Sie?

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



Dies verschiebt nur die id ‚s um 1 und vergleicht sie mit ID für benachbarte Spiele zu überprüfen.
Dann für die Dat-Subtraktion einfach die Übereinstimmungen vom Datum der folgenden Zeile subtrahieren.

0

In dem Fall, dass Sie eine komplexere Formel benötigen, können Sie Aggregat verwenden:

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

Die gleiche Sortierreihenfolge gilt auch hier, wie in @nograpes beantworten.

Verwandte Themen