J'ai un data.table avec environ 3 millions de lignes et 40 colonnes. Je voudrais trier ce tableau par ordre décroissant au sein de groupes comme le code simulé sql suivant:
sort by ascending Year, ascending MemberID, descending Month
Existe-t-il un moyen équivalent dans data.table de le faire? Jusqu'à présent, je dois le décomposer en 2 étapes:
setkey(X, Year, MemberID)
C'est très rapide et ne prend que quelques secondes.
X <- X[,.SD[order(-Month)],by=list(Year, MemberID)]
Cette étape prend beaucoup plus de temps (5 minutes).
Mise à jour: Quelqu'un a fait un commentaire pour faire X <- X[sort(Year, MemberID, -Month)]
et supprimé plus tard. Cette approche semble être beaucoup plus rapide:
user system elapsed
5.560 11.242 66.236
Mon approche: setkey () puis order (-Month)
user system elapsed
816.144 9.648 848.798
Ma question est maintenant: si je veux résumer par année, MemberId et mois après le tri (année, MemberID, mois), data.table reconnaît-il l'ordre de tri?
Mise à jour 2: pour répondre à Matthew Dowle:
Après avoir défini setkey avec Year, MemberID et Month, j'ai toujours plusieurs enregistrements par groupe. Je voudrais résumer pour chacun des groupes. Ce que je voulais dire était: si j'utilise X [commande (année, ID membre, mois)], la sommation utilise-t-elle la fonctionnalité de recherche binaire de data.table:
monthly.X <- X[, lapply(.SD[], sum), by = list(Year, MemberID, Month)]
Mise à jour 3: Matthew D a proposé plusieurs approches. Le temps d'exécution de la première approche est plus rapide que l'approche order ():
user system elapsed
7.910 7.750 53.916
Matthew: ce qui m'a surpris, c'est de convertir le signe du mois prend la plupart du temps. Sans cela, setkey est extrêmement rapide.
La version de développement actuelle de data.table v1.9.3 a deux nouvelles fonctions implémentées, à savoir: setorder
et setorderv
, qui fait exactement ce dont vous avez besoin. Ces fonctions réorganisent le data.table
par référence avec la possibilité de choisir un ordre croissant ou décroissant sur chaque colonne pour classer par. Consultez ?setorder
Pour plus d'informations.
De plus, DT[order(.)]
est également optimisé par défaut pour utiliser l'ordre rapide interne de data.table
au lieu de base:::order
. Contrairement à setorder
, cela fera une copie entière des données, et est donc moins efficace en mémoire, mais sera toujours plus rapide que de fonctionner en utilisant l'ordre de base.
Voici une illustration des différences de vitesse en utilisant setorder
, l'ordre rapide interne de data.table et avec base:::order
:
require(data.table) ## 1.9.3
set.seed(1L)
DT <- data.table(Year = sample(1950:2000, 3e6, TRUE),
memberID = sample(paste0("V", 1:1e4), 3e6, TRUE),
month = sample(12, 3e6, TRUE))
## using base:::order
system.time(ans1 <- DT[base:::order(Year, memberID, -month)])
# user system elapsed
# 76.909 0.262 81.266
## optimised to use data.table's fast order
system.time(ans2 <- DT[order(Year, memberID, -month)])
# user system elapsed
# 0.985 0.030 1.027
## reorders by reference
system.time(setorder(DT, Year, memberID, -month))
# user system elapsed
# 0.585 0.013 0.600
## or alternatively
## setorderv(DT, c("Year", "memberID", "month"), c(1,1,-1))
## are they equal?
identical(ans2, DT) # [1] TRUE
identical(ans1, ans2) # [1] TRUE
Sur ces données, les benchmarks indiquent que l'ordre de data.table est environ ~ 79x plus rapide que base:::order
Et setorder
est ~ 135x plus rapide que base:::order
Ici.
data.table
Trie/commande toujours en C-locale. Si vous devez commander dans un autre pays, vous devez alors utiliser DT[base:::order(.)]
.
Toutes ces nouvelles optimisations et fonctions constituent ensemble FR # 2405 . le support bit64 :: integer64 a également été ajouté .
REMARQUE: Veuillez vous référer à l'historique/révisions pour une réponse et des mises à jour antérieures.
Le commentaire était le mien, donc je posterai la réponse. Je l'ai supprimé car je n'ai pas pu tester s'il était équivalent à ce que vous aviez déjà. Heureux d'entendre que c'est plus rapide.
X <- X[order(Year, MemberID, -Month)]
Le résumé ne devrait pas dépendre de l'ordre de vos lignes.