Dois-je investir mon effort d'apprentissage pour la lutte des données dans R, en particulier entre dplyr
, dtplyr
et data.table
?
J'utilise
dplyr
principalement, mais lorsque les données sont trop volumineuses pour cela, je vais les utiliserdata.table
, ce qui est rare. Alors maintenant que ladtplyr
v1.0 est sortie en tant qu'interfacedata.table
, il semble que je n'ai plus jamais à me soucier dedata.table
réutiliser l' interface.Quelles sont donc les fonctionnalités ou les aspects les plus utiles
data.table
qui ne peuvent pas être utilisésdtplyr
pour le moment, et qui ne seront probablement jamais réalisés avecdtplyr
?Sur son visage,
dplyr
avec les avantages dedata.table
sonne comme undtplyr
dépassementdplyr
. Y aura-t-il une raison d'utiliserdplyr
une fois qu'ildtplyr
est complètement arrivé à maturité?
Remarque: je ne pose pas de question sur dplyr
vsdata.table
(comme dans data.table vs dplyr: l'un peut-il faire quelque chose de bien l'autre ne peut pas ou fait mal? ), Mais étant donné que l'un est préféré à l'autre pour un problème particulier, pourquoi ne le ferait-il pas? t dtplyr
être l'outil à utiliser.
la source
dplyr
lequel vous ne pouvez pas bien fairedata.table
? Sinon, passer àdata.table
va être meilleur quedtplyr
.dtplyr
readme, «Certainesdata.table
expressions n'ont pas d'dplyr
équivalent direct . Par exemple, il n'y a aucun moyen d'exprimer des jointures croisées ou continuesdplyr
. et 'Pour faire correspondre ladplyr
sémantique,mutate
() ne modifie pas en place par défaut. Cela signifie que la plupart des expressions impliquantmutate()
doivent faire une copie qui ne serait pas nécessaire si vous l'utilisiezdata.table
directement. ' Il y a un peu un moyen de contourner cette deuxième partie, mais compte tenu de la fréquence d'mutate
utilisation, c'est un gros inconvénient à mes yeux.Réponses:
Je vais essayer de vous donner mes meilleurs guides mais ce n'est pas facile car il faut être familier avec tous les {data.table}, {dplyr}, {dtplyr} et aussi {base R}. J'utilise {data.table} et de nombreux packages {tidy-world} (sauf {dplyr}). J'adore les deux, bien que je préfère la syntaxe de data.table à celle de dplyr. J'espère que tous les packages tidy-world utiliseront {dtplyr} ou {data.table} comme backend chaque fois que cela sera nécessaire.
Comme pour toute autre traduction (pensez dplyr-to-sparkly / SQL), il y a des choses qui peuvent ou ne peuvent pas être traduites, du moins pour l'instant. Je veux dire, peut-être qu'un jour {dtplyr} pourra le traduire à 100%, qui sait. La liste ci-dessous n'est pas exhaustive ni 100% correcte car je ferai de mon mieux pour répondre en fonction de mes connaissances sur des sujets / packages / problèmes / etc.
Surtout, pour ces réponses qui ne sont pas entièrement exactes, j'espère que cela vous donne quelques guides sur les aspects de {data.table} auxquels vous devez prêter attention et, comparez-le à {dtplyr} et découvrez les réponses par vous-même. Ne prenez pas ces réponses pour acquises.
Et j'espère que ce message peut être utilisé comme l'une des ressources pour tous les utilisateurs / créateurs {dplyr}, {data.table} ou {dtplyr} pour des discussions et des collaborations et améliorer encore #RStats.
{data.table} n'est pas seulement utilisé pour des opérations rapides et efficaces en mémoire. Il y a beaucoup de gens, y compris moi-même, qui préfèrent la syntaxe élégante de {data.table}. Il comprend également d'autres opérations rapides comme les fonctions de séries chronologiques comme la famille de roulement (c'est-à-dire
frollapply
) écrites en C. Il peut être utilisé avec toutes les fonctions, y compris tidyverse. J'utilise beaucoup {data.table} + {purrr}!Complexité des opérations
Cela peut être facilement traduit
{data.table} est très rapide et efficace en mémoire car (presque?) tout est construit à partir de zéro à partir de C avec les concepts clés de mise à jour par référence , clé (pensez SQL), et leur optimisation implacable partout dans le package (c'est-à
fifelse
- dire , l'fread/fread
ordre de tri radix adopté par la base R), tout en s'assurant que la syntaxe est concise et cohérente, c'est pourquoi je pense que c'est élégant.De l' introduction à data.table , les principales opérations de manipulation de données telles que le sous-ensemble, le groupe, la mise à jour, la jointure, etc. sont conservées ensemble pour
syntaxe concise et cohérente ...
effectuer une analyse fluide sans la charge cognitive d'avoir à cartographier chaque opération ...
optimisation automatique des opérations en interne et très efficacement, en connaissant précisément les données requises pour chaque opération, conduisant à un code très rapide et efficace en mémoire
Le dernier point, à titre d'exemple,
Étant donné que, pour profiter des avantages de {data.table}, la traduction de {dtplr} doit être correcte à cet égard. Plus les opérations sont complexes, plus les traductions sont dures. Pour les opérations simples comme ci-dessus, il peut certainement être facilement traduit. Pour les complexes, ou ceux qui ne sont pas pris en charge par {dtplyr}, vous devez vous renseigner comme mentionné ci-dessus, il faut comparer la syntaxe traduite et le benchmark et être des packages familiers.
Pour les opérations complexes ou les opérations non prises en charge, je pourrais être en mesure de fournir quelques exemples ci-dessous. Encore une fois, je fais de mon mieux. Soyez doux avec moi.
Mise à jour par référence
Je n'entrerai pas dans l'intro / détails mais voici quelques liens
Ressource principale: Sémantique de référence
Plus de détails: Comprendre exactement quand un data.table est une référence à (vs une copie de) un autre data.table
Mise à jour par référence , à mon avis, la caractéristique la plus importante de {data.table} et c'est ce qui la rend si rapide et efficace en mémoire.
dplyr::mutate
ne le prend pas en charge par défaut. Comme je ne connais pas {dtplyr}, je ne sais pas combien et quelles opérations peuvent ou ne peuvent pas être prises en charge par {dtplyr}. Comme mentionné ci-dessus, cela dépend également de la complexité des opérations, qui à leur tour affectent les traductions.Il existe deux façons d'utiliser la mise à jour par référence dans {data.table}
opérateur d'affectation de {data.table}
:=
set
-family:set
,setnames
,setcolorder
,setkey
,setDT
,fsetdiff
, et beaucoup d' autres:=
est plus couramment utilisé par rapport àset
. Pour les ensembles de données complexes et volumineux, la mise à jour par référence est la clé pour obtenir une vitesse maximale et une efficacité de la mémoire. La façon de penser facile (pas précise à 100%, car les détails sont beaucoup plus compliqués que cela car cela implique une copie dure / peu profonde et de nombreux autres facteurs), disons que vous avez affaire à un grand ensemble de données de 10 Go, avec 10 colonnes et 1 Go chacune . Pour manipuler une colonne, vous devez traiter uniquement 1 Go.Le point clé est, avec la mise à jour par référence , il vous suffit de traiter les données requises. C'est pourquoi lorsque vous utilisez {data.table}, en particulier pour les grands ensembles de données, nous utilisons la mise à jour par référence tout le temps possible. Par exemple, manipuler un grand ensemble de données de modélisation
L'opération d'imbrication
list(.SD)
peut ne pas être prise en charge par {dtlyr} comme les utilisateurs de tidyverse l'utilisenttidyr::nest
? Donc, je ne sais pas si les opérations suivantes peuvent être traduites comme la manière de {data.table} est plus rapide et moins de mémoire.REMARQUE: le résultat de data.table est en "milliseconde", dplyr en "minute"
Il existe de nombreux cas d'utilisation de la mise à jour par référence et même les utilisateurs de {data.table} n'en utiliseront pas la version avancée tout le temps car ils nécessitent plus de codes. Que {dtplyr} prenne en charge ces éléments prêts à l'emploi, vous devez vous renseigner.
Mise à jour multiple par référence pour les mêmes fonctions
Ressource principale: Affectation élégante de plusieurs colonnes dans data.table avec lapply ()
Cela implique soit le plus couramment utilisé
:=
soitset
.Selon le créateur de {data.table} Matt Dowle
Join + setkey + update-by-reference
J'ai eu besoin d'une jointure rapide avec des données relativement volumineuses et des modèles de jointure similaires récemment, donc j'utilise la puissance de la mise à jour par référence , au lieu des jointures normales. Comme ils nécessitent plus de codes, je les enveloppe dans un package privé avec une évaluation non standard pour la réutilisabilité et la lisibilité où je l'appelle
setjoin
.J'ai fait un benchmark ici: data.table join + update-by-reference + setkey
Sommaire
REMARQUE:
dplyr::left_join
a également été testé et c'est le plus lent avec environ 9 000 ms, utilisez plus de mémoire que {data.table}update_by_reference
etsetkey_n_update
, mais utilisez moins de mémoire que normal_join de {data.table}. Il a consommé environ ~ 2,0 Go de mémoire. Je ne l'ai pas inclus car je veux me concentrer uniquement sur {data.table}.Principales conclusions
setkey + update
etupdate
sont ~ 11 et ~ 6,5 fois plus rapides quenormal join
, respectivementsetkey + update
est similaire àupdate
celle des frais générauxsetkey
qui compense largement ses propres gains de performancesetkey
n'est pas nécessaire,setkey + update
est plus rapide queupdate
~ 1,8 fois (ou plus rapide quenormal join
~ 11 fois)Exemples
Pour des jointures performantes et efficaces en mémoire, utilisez soit
update
ousetkey + update
, lorsque ce dernier est plus rapide au prix de plus de codes.Voyons quelques pseudo codes, par souci de concision. Les logiques sont les mêmes.
Pour une ou quelques colonnes
Pour de nombreuses colonnes
Wrapper pour des jointures rapides et efficaces en mémoire ... beaucoup d'entre elles ... avec un modèle de jointure similaire, enveloppez-les comme
setjoin
ci-dessus - avecupdate
- avec ou sanssetkey
Avec
setkey
, l'argumenton
peut être omis. Il peut également être inclus pour plus de lisibilité, en particulier pour collaborer avec d'autres.Fonctionnement sur grande rangée
set
setkey
)Ressource associée: Ajouter une ligne par référence à la fin d'un objet data.table
Résumé de la mise à jour par référence
Ce ne sont que quelques cas d'utilisation de la mise à jour par référence . Il y en a bien d'autres.
Comme vous pouvez le voir, pour une utilisation avancée du traitement des données volumineuses, il existe de nombreux cas d'utilisation et techniques utilisant la mise à jour par référence pour un grand ensemble de données. Ce n'est pas si facile à utiliser dans {data.table} et si {dtplyr} le prend en charge, vous pouvez le découvrir vous-même.
Je me concentre sur la mise à jour par référence dans ce post car je pense que c'est la fonctionnalité la plus puissante de {data.table} pour des opérations rapides et efficaces en mémoire. Cela dit, il y a beaucoup, beaucoup d'autres aspects qui le rendent aussi efficace et je pense qu'ils ne sont pas supportés nativement par {dtplyr}.
Autres aspects clés
Ce qui est / n'est pas pris en charge, cela dépend également de la complexité des opérations et si cela implique la fonctionnalité native de data.table comme la mise à jour par référence ou
setkey
. Et si le code traduit est le plus efficace (celui que les utilisateurs de data.table écriraient) est également un autre facteur (c'est-à-dire que le code est traduit, mais est-ce la version efficace?). Beaucoup de choses sont interconnectées.setkey
. Voir Clés et sous-ensemble basé sur la recherche binaire rapidefrollapply
. fonctions de roulement, agrégats de roulement, fenêtre coulissante, moyenne mobilei
,j
ou desby
opérations (vous pouvez utiliser presque toutes les expressions là - dedans), je pense que les plus dures traductions, surtout quand il se combiner avec la mise à jour par référence ,setkey
et d' autres data.table native des fonctions commefrollapply
stringr::str_*
famille vs base R et je trouve que la base R est plus rapide dans une certaine mesure et les utilise. Le point est, ne vous limitez pas à seulement tidyverse ou data.table ou ..., explorez d'autres options pour faire le travail.Beaucoup de ces aspects sont liés aux points mentionnés ci-dessus
complexité des opérations
mise à jour par référence
Vous pouvez savoir si {dtplyr} prend en charge ces opérations, en particulier lorsqu'elles sont combinées.
Autre astuce utile lors de la manipulation de petits ou de grands ensembles de données, lors d'une session interactive, {data.table} tient vraiment sa promesse de réduire considérablement la programmation et le temps de calcul .
Clé de réglage pour la variable utilisée de manière répétitive à la fois pour la vitesse et les «noms de domaine suralimentés» (sous-ensemble sans spécifier le nom de la variable).
Si vos opérations impliquent uniquement des opérations simples comme dans le premier exemple, {dtplyr} peut faire le travail. Pour les fichiers complexes / non pris en charge, vous pouvez utiliser ce guide pour comparer les fichiers traduits de {dtplyr} avec la façon dont les utilisateurs expérimentés de data.table coderaient de manière rapide et efficace en mémoire avec la syntaxe élégante de data.table. La traduction ne signifie pas que c'est le moyen le plus efficace car il peut y avoir différentes techniques pour traiter différents cas de données volumineuses. Pour un ensemble de données encore plus volumineux, vous pouvez combiner {data.table} avec {disk.frame} , {fst} et {drake} et d'autres packages impressionnants pour en tirer le meilleur . Il existe également un {big.data.table} mais il est actuellement inactif.
J'espère que cela aide tout le monde. Passez une bonne journée ☺☺
la source
Les jointures non équi et les jointures tournantes viennent à l'esprit. Il ne semble pas être prévu d'inclure des fonctions équivalentes dans dplyr, il n'y a donc rien à traduire pour dtplyr.
Il y a aussi un remodelage (optimisation de diffusion et fusion optimisées équivalant aux mêmes fonctions dans reshape2) qui n'est pas également dans dplyr.
Actuellement, toutes les fonctions * _if et * _at ne peuvent pas être traduites avec dtplyr mais celles-ci sont en préparation.
la source
Mettre à jour une colonne lors de la jointure Quelques astuces .SD Beaucoup de fonctions f Et Dieu sait quoi d'autre parce que #rdatatable est plus qu'une simple bibliothèque et il ne peut pas être résumé avec peu de fonctions
C'est un écosystème à part entière
Je n'ai jamais eu besoin de dplyr depuis le jour où j'ai commencé R. Parce que data.table est tellement bon
la source