2012-08-26 30 views
12

Mam następujący ramkę danych:Znajdź maksymalny termin dla każdego ID

id<-c(1,1,2,3,3) 
date<-c("23-01-08","01-11-07","30-11-07","17-12-07","12-12-08") 
df<-data.frame(id,date) 
df$date2<-as.Date(as.character(df$date), format = "%d-%m-%y") 


id  date  date2 
1 23-01-08 2008-01-23 
1 01-11-07 2007-11-01 
2 30-11-07 2007-11-30 
3 17-12-07 2007-12-17 
3 12-12-08 2008-12-12 

teraz muszę utworzyć kolumnę Forth i wstawić maksymalną datę transakcji dla każdego id w tym. ostateczna tabela powinna być następująca:

id  date  date2  max 
1 23-01-08 2008-01-23 2008-01-23 
1 01-11-07 2007-11-01 0 
2 30-11-07 2007-11-30 2007-11-30 
3 17-12-07 2007-12-17 0 
3 12-12-08 2008-12-12 2008-12-12 

Byłbym wdzięczny, gdyby mógł mi w tym pomóc.

Odpowiedz

18
id<-c(1,1,2,3,3) 
date<-c("23-01-08","01-11-07","30-11-07","17-12-07","12-12-08") 
df<-data.frame(id,date) 
df$date2<-as.Date(as.character(df$date), format = "%d-%m-%y") 
# aggregate can be used for this type of thing 
d = aggregate(df$date2,by=list(df$id),max) 
# And merge the result of aggregate 
# with the original data frame 
df2 = merge(df,d,by.x=1,by.y=1) 
df2 

    id  date  date2   x 
1 1 23-01-08 2008-01-23 2008-01-23 
2 1 01-11-07 2007-11-01 2008-01-23 
3 2 30-11-07 2007-11-30 2007-11-30 
4 3 17-12-07 2007-12-17 2008-12-12 
5 3 12-12-08 2008-12-12 2008-12-12 

Edycja: Ponieważ chcesz ostatnia kolumna jest „pusty”, gdy data nie pasuje termin maksymalny, można spróbować następnego wiersza.

df2[df2[,3]!=df2[,4],4]=NA 

df2 
    id  date  date2   x 
1 1 23-01-08 2008-01-23 2008-01-23 
2 1 01-11-07 2007-11-01  <NA> 
3 2 30-11-07 2007-11-30 2007-11-30 
4 3 17-12-07 2007-12-17  <NA> 
5 3 12-12-08 2008-12-12 2008-12-12 

Oczywiście zawsze dobrze jest posprzątać nazwy, itp., Ale zostawiam to za Ciebie.

2
library(sqldf) 
tables<- '(SELECT * FROM df 
      ) 
      AS t1, 
      (SELECT id,max(date2) date2 FROM df GROUP BY id 
      ) 
      AS t2' 

out<-fn$sqldf("SELECT t1.*,t2.date2 mdate FROM $tables WHERE t1.id=t2.id") 
out$mdate<-as.Date(out$mdate) 
out$mdate[out$date2!=out$mdate]<-NA 
# id  date  date2  mdate 
#1 1 01-11-07 2007-11-01  <NA> 
#2 1 23-01-08 2008-01-23 2008-01-23 
#3 2 30-11-07 2007-11-30 2007-11-30 
#4 3 12-12-08 2008-12-12 2008-12-12 
#5 3 17-12-07 2007-12-17  <NA> 
1

Nie można użyć 0 jako wartość daty, więc albo trzeba porzucić utrzymanie go jako data lub przyjąć wartość na:

# Date values: 
df$maxdt <- ave(df$date2, df$id, 
        FUN=function(x) ifelse(x == max(x), as.character(x), NA)) 
str(ave(df$date2, df$id, FUN=function(x) ifelse(x == max(x), as.character(x), NA))) 
# Date[1:5], format: "2008-01-23" NA "2007-11-30" NA "2008-12-12" 

Maszyna ifelse robi jakiś dziwny sprawdzanie typu, które porażki używające tylko x jako drugiego argumentu powyżej, ale wciąż zwraca wektor klasy Date. Domyśl! Poniżej znajduje się opcja wektora postaci.

# Character values: 
df$maxdt <- ave(as.character(df$date2), df$id, 
        FUN=function(x) ifelse(x == max(x), x, "0")) 
ave(as.character(df$date2), df$id, FUN=function(x) ifelse(x == max(x), x, "0")) 
[1] "2008-01-23" "0"   "2007-11-30" "0"   "2008-12-12" 
7

Innym podejściem jest użycie pakietu plyr:

library(plyr) 
ddply(df, "id", summarize, max = max(date2)) 

# id  max 
#1 1 2008-01-23 
#2 2 2007-11-30 
#3 3 2008-12-12 

Teraz to nie jest w formacie byłeś po, jak to tylko pokazuje każdy id raz. Nie bój się, możemy użyć transform zamiast summarize:

ddply(df, "id", transform, max = max(date2)) 

# id  date  date2  max 
#1 1 01-11-07 2007-11-01 2008-01-23 
#2 1 23-01-08 2008-01-23 2008-01-23 
#3 2 30-11-07 2007-11-30 2007-11-30 
#4 3 12-12-08 2008-12-12 2008-12-12 
#5 3 17-12-07 2007-12-17 2008-12-12 

Ponieważ w odpowiedzi @ seandavi, ten powtarza max datę dla każdego id. Jeśli chcesz zmienić duplikaty do NA, coś jak to będzie wykonać zadanie:

within(ddply(df, "id", transform, max = max(date2)), max[max != date2] <- NA) 
2

Dodawanie dplyr rozwiązanie w przypadku gdy ktoś patrzy:

library(dplyr) 

df %>% 
    group_by(id) %>% 
    mutate(max = if_else(date2 == max(date2), date2, as.Date(NA))) 

Wynik:

# A tibble: 5 x 4 
# Groups: id [3] 
    id  date  date2  max 
    <dbl> <fctr>  <date>  <date> 
1  1 23-01-08 2008-01-23 2008-01-23 
2  1 01-11-07 2007-11-01   NA 
3  2 30-11-07 2007-11-30 2007-11-30 
4  3 17-12-07 2007-12-17   NA 
5  3 12-12-08 2008-12-12 2008-12-12 
+0

Używam go w ten sposób: mutate (flag_last = if_else (date == max (date), TRUE, FALSE))%>% filter (flag_last == TRUE) – Rohit

Powiązane problemy