Aperçu
Je suis relativement familier data.table
, pas tellement dplyr
. J'ai lu quelques dplyr
vignettes et exemples qui ont surgi sur SO, et jusqu'à présent, mes conclusions sont les suivantes:
data.table
etdplyr
sont comparables en vitesse, sauf lorsqu'il existe de nombreux groupes (c.-à-d.> 10-100K) et dans certaines autres circonstances (voir les repères ci-dessous)dplyr
a une syntaxe plus accessibledplyr
résume (ou fera) les interactions DB potentielles- Il y a quelques différences de fonctionnalités mineures (voir "Exemples / Utilisation" ci-dessous)
Dans mon esprit, 2. n'a pas beaucoup de poids car je le connais assez bien data.table
, même si je comprends que pour les utilisateurs novices, ce sera un facteur important. Je voudrais éviter un argument qui est plus intuitif, car cela n'est pas pertinent pour ma question spécifique posée du point de vue de quelqu'un qui est déjà familier data.table
. Je voudrais également éviter une discussion sur la façon dont "plus intuitif" conduit à une analyse plus rapide (certainement vrai, mais encore une fois, pas ce qui m'intéresse le plus ici).
Question
Ce que je veux savoir c'est:
- Y a-t-il des tâches analytiques qui sont beaucoup plus faciles à coder avec l'un ou l'autre package pour les personnes familières avec les packages (c'est-à-dire une combinaison de touches requise par rapport au niveau requis d'ésotérisme, où moins de chacun est une bonne chose).
- Existe-t-il des tâches analytiques qui sont exécutées de manière substantielle (c'est-à-dire plus de 2x) plus efficacement dans un package par rapport à un autre?
Une question récente sur les SO m'a fait réfléchir un peu plus, car jusqu'à ce moment-là, je ne pensais pas dplyr
offrir beaucoup plus que ce que je pouvais déjà faire data.table
. Voici la dplyr
solution (données en fin de Q):
dat %.%
group_by(name, job) %.%
filter(job != "Boss" | year == min(year)) %.%
mutate(cumu_job2 = cumsum(job2))
Ce qui était bien mieux que ma tentative de piratage pour data.table
trouver une solution. Cela dit, les bonnes data.table
solutions sont également assez bonnes (merci Jean-Robert, Arun, et notez ici que j'ai préféré une seule déclaration à la solution strictement la plus optimale):
setDT(dat)[,
.SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)],
by=list(id, job)
]
La syntaxe de ce dernier peut sembler très ésotérique, mais elle est en fait assez simple si vous en avez l'habitude data.table
(c'est- à -dire qu'elle n'utilise pas certaines des astuces les plus ésotériques).
Idéalement, ce que j'aimerais voir, ce sont de bons exemples où la manière dplyr
ou data.table
est beaucoup plus concise ou fonctionne beaucoup mieux.
Exemples
Usagedplyr
ne permet pas les opérations groupées qui retournent un nombre arbitraire de lignes (à partir de la question d' eddi , remarque: cela semble être implémenté dans dplyr 0.5 , également, @beginneR montre une solution de contournement potentielle à utiliserdo
dans la réponse à la question de @ eddi).data.table
prend en charge les jointures roulantes (merci @dholstius) ainsi que les jointures à chevauchementdata.table
optimise en interne les expressions du formulaireDT[col == value]
ouDT[col %in% values]
pour la vitesse grâce à l'indexation automatique qui utilise la recherche binaire tout en utilisant la même syntaxe de base R. Voir ici pour plus de détails et une petite référence.dplyr
offre des versions d'évaluation standard de fonctions (par exempleregroup
,summarize_each_
) qui peuvent simplifier l'utilisation programmatique dedplyr
(notez que l'utilisation programmatique dedata.table
est certainement possible, nécessite juste une réflexion, une substitution / citation, etc., au moins à ma connaissance)
- J'ai exécuté mes propres tests de performance et j'ai trouvé que les deux packages étaient comparables dans l'analyse de style "split apply combine", sauf quand il y a un très grand nombre de groupes (> 100K) à quel point
data.table
devient considérablement plus rapide. - @Arun a exécuté des tests de performance sur les jointures , montrant que les
data.table
échelles sont meilleures quedplyr
lorsque le nombre de groupes augmente (mis à jour avec les améliorations récentes des packages et de la version récente de R). En outre, une référence lors de la tentative d'obtention de valeurs uniques estdata.table
environ 6 fois plus rapide. - (Non vérifié) a
data.table
75% plus rapide sur les versions plus grandes d'un groupe / appliquer / trier tandis qu'ildplyr
était 40% plus rapide sur les plus petites ( une autre question SO des commentaires , merci danas). - Matt, l'auteur principal de
data.table
, a benchmarkée des opérations de regroupement surdata.table
,dplyr
et pythonpandas
sur un maximum de 2 milliards de lignes (~ 100 Go en RAM) . - Une référence plus ancienne sur les groupes 80K a
data.table
~ 8 fois plus rapide
Les données
Ceci est le premier exemple que j'ai montré dans la section des questions.
dat <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L), name = c("Jane", "Jane", "Jane", "Jane",
"Jane", "Jane", "Jane", "Jane", "Bob", "Bob", "Bob", "Bob", "Bob",
"Bob", "Bob", "Bob"), year = c(1980L, 1981L, 1982L, 1983L, 1984L,
1985L, 1986L, 1987L, 1985L, 1986L, 1987L, 1988L, 1989L, 1990L,
1991L, 1992L), job = c("Manager", "Manager", "Manager", "Manager",
"Manager", "Manager", "Boss", "Boss", "Manager", "Manager", "Manager",
"Boss", "Boss", "Boss", "Boss", "Boss"), job2 = c(1L, 1L, 1L,
1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L)), .Names = c("id",
"name", "year", "job", "job2"), class = "data.frame", row.names = c(NA,
-16L))
dplyr
et les data.table
équipes travaillent sur des repères, donc une réponse sera là à un moment donné. # 2 (syntaxe) imO est strictement faux, mais cela s'aventure clairement en territoire d'opinion, donc je vote pour fermer aussi.
(d)plyr
a la mesure 0
dplyr
et plyr
en ce qui concerne la syntaxe et est fondamentalement la principale raison pour laquelle je n'aime pas leur syntaxe, est que je dois apprendre beaucoup trop (lire plus de 1) des fonctions supplémentaires (avec des noms qui encore ça n'a pas de sens pour moi), rappelez-vous ce qu'ils font, quels arguments ils soutiennent, etc.
.SD
). [sérieusement] Je pense que ce sont des différences de conception légitimes qui
dplyr
ci est:as.data.table(dat)[, .SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)], by = list(name, job)]