web-dev-qa-db-fra.com

Trouver la date maximale dans une seule colonne sur plusieurs lignes

J'ai le cadre de données suivant:

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

maintenant, je dois créer une quatrième colonne et insérer la date de transaction maximale pour chaque id dans celle-ci. La table finale devrait être comme suit:

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

Je serais reconnaissant si vous pouviez m'aider avec ceci.

13
AliCivil
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

Éditer: puisque vous voulez que la dernière colonne soit "vide" lorsque la date ne correspond pas à la date maximale, vous pouvez essayer la ligne suivante. 

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

Bien sûr, il est toujours agréable de nettoyer les noms de pays, etc., mais je vous laisse cela.

21
seandavi

Une autre approche consiste à utiliser le package 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

Maintenant, ce n’est pas dans le format que vous recherchiez, car il ne montre que chaque id une fois. Ne craignez rien, nous pouvons utiliser transform au lieu de 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

Comme dans la réponse de @ seandavi, cela répète la date max pour chaque id. Si vous souhaitez modifier les doublons en NA, une chose comme celle-ci fera l'affaire:

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

Ajout de la solution dplyr au cas où quelqu'un regarderait:

library(dplyr)

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

Résultat:

# 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
6
avid_useR
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>
2

Vous ne pouvez pas utiliser 0 comme valeur de date. Vous devrez donc abandonner la conservation comme date ou accepter une valeur 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"

La machine ifelse effectue une vérification de type étrange qui échoue en utilisant simplement x comme deuxième argument ci-dessus, mais renvoie toujours le vecteur Date-class. Allez comprendre! Ci-dessous, l’option de vecteur de caractère.

# 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"
2
42-

J'ai trouvé ceci pour m'aider quand je veux voir la date min/max d'une colonne 

Max: head(df %>% distinct(date) %>% arrange(desc(date)))
Min: head(df %>% distinct(date) %>% arrange(date))

Le max va trier la colonne de date par ordre décroissant, vous permettant de voir le max. Le min va trier par ordre croissant, vous permettant de voir le min. 

Vous devez utiliser le package dplyr pour cela.

0
grantog