2012-11-27 9 views
5

Mam zestaw danych, który wygląda tak:Oblicz różnice między rzędami szybciej niż w pętli for?

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

Więc załadować powyższy fragment jako ramki danych, kod jest:

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) 


Próbuję dodać kolumna, która oblicza "dni od ostatniego rekordu dla tego ID".

Teraz używam pętli FOR, który wygląda mniej więcej tak:

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


istnieje szybszy sposób to zrobić? (Wyglądałem trochę na APLIKACJĘ, ale nie mogę znaleźć rozwiązania poza pętlą FOR.)

Z góry dziękuję!

+2

Proszę dodać do pytania wynik działania 'dput (head (data))'. Twoje daty nie wyglądają jak coś, co możesz odjąć – GSee

+1

Istnieje wiele sposobów podejścia do kawałka split-apply, ale wszystkie z nich prawdopodobnie zakończą się używaniem 'diff'. – joran

+0

@GSee - nie pokazałem tego, ale przekonwertowałem daty już używające jako.Date(). Powyższe dane są jedynie fikcyjnymi danymi do zilustrowania struktury. –

Odpowiedz

5

Powinno to działać, jeśli daty są podane w zakresie od 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

(Moja edycja dodała linię zamówienia) –

+0

(Bez zmian.) Przepraszam za to.) –

0

W jaki sposób następujące czynności dla Ciebie działają?

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



To właśnie przesuwa id „s o 1 i porównuje je do ID, aby sprawdzić sąsiednich meczów.
Następnie dla odejmowania dat, po prostu odejmij dopasowania od daty następnego rzędu.

0

W przypadku, gdy trzeba bardziej skomplikowany wzór, można użyć kruszywo:

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

Ten sam porządek obowiązuje tu jak w @nograpes odpowiedzieć.

Powiązane problemy