J'ai essayé d'utiliser un peu plus les fonctions "split" et "tapply" pour me familiariser avec elles. Je sais que cette question a déjà reçu une réponse mais j'ai pensé ajouter une autre solution en utilisant split (pardonnez la laideur ; je suis plus qu'ouvert aux commentaires pour l'amélioration ; j'ai pensé qu'il y avait peut-être une utilité à tapply pour alléger le code) :
sdf <-with(df, split(df, ID))
max.week <- sapply(seq_along(sdf), function(x) which.max(sdf[[x]][, 'week']))
data.frame(t(mapply(function(x, y) y[x, ], max.week, sdf)))
Je me suis également demandé pourquoi nous avions 7 réponses ici, c'était mûr pour une analyse comparative. Les résultats peuvent vous surprendre (en utilisant rbenchmark avec R2.14.1 sur une machine Win 7) :
# library(rbenchmark)
# benchmark(
# DATA.TABLE= {dt <- data.table(df, key="ID")
# dt[, .SD[which.max(outcome),], by=ID]},
# DO.CALL={do.call("rbind",
# by(df, INDICES=df$ID, FUN=function(DF) DF[which.max(DF$week),]))},
# PLYR=ddply(df, .(ID), function(X) X[which.max(X$week), ]),
# SPLIT={sdf <-with(df, split(df, ID))
# max.week <- sapply(seq_along(sdf), function(x) which.max(sdf[[x]][, 'week']))
# data.frame(t(mapply(function(x, y) y[x, ], max.week, sdf)))},
# MATCH.INDEX=df[rev(rownames(df)),][match(unique(df$ID), rev(df$ID)), ],
# AGGREGATE=df[cumsum(aggregate(week ~ ID, df, which.max)$week), ],
# #WHICH.MAX.INDEX=df[sapply(unique(df$ID), function(x) which.max(x==df$ID)), ],
# BRYANS.INDEX = df[cumsum(as.numeric(lapply(split(df$week, df$ID),
# which.max))), ],
# SPLIT2={sdf <-with(df, split(df, ID))
# df[cumsum(sapply(seq_along(sdf), function(x) which.max(sdf[[x]][, 'week']))),
# ]},
# TAPPLY=df[tapply(seq_along(df$ID), df$ID, function(x){tail(x,1)}),],
# columns = c( "test", "replications", "elapsed", "relative", "user.self","sys.self"),
# order = "test", replications = 1000, environment = parent.frame())
test replications elapsed relative user.self sys.self
6 AGGREGATE 1000 4.49 7.610169 2.84 0.05
7 BRYANS.INDEX 1000 0.59 1.000000 0.20 0.00
1 DATA.TABLE 1000 20.28 34.372881 11.98 0.00
2 DO.CALL 1000 4.67 7.915254 2.95 0.03
5 MATCH.INDEX 1000 1.07 1.813559 0.51 0.00
3 PLYR 1000 10.61 17.983051 5.07 0.00
4 SPLIT 1000 3.12 5.288136 1.81 0.00
8 SPLIT2 1000 1.56 2.644068 1.28 0.00
9 TAPPLY 1000 1.08 1.830508 0.88 0.00
Éditer1 : J'ai omis la solution WHICH MAX car elle ne renvoie pas les bons résultats et j'ai renvoyé une solution AGGREGATE que je voulais utiliser (avec les compliments de Bryan Goodrich) et une version actualisée de split, SPLIT2, qui utilise cumsum (j'ai aimé ce changement).
Editer 2 : Dason a également fait part d'une solution d'application que j'ai proposée dans le cadre du test et qui s'est avérée très efficace.