Par exemple (je ne sais pas si l'exemple le plus représentatif):
N <- 1e6
d1 <- data.frame(x=sample(N,N), y1=rnorm(N))
d2 <- data.frame(x=sample(N,N), y2=rnorm(N))
Voici ce que j'ai jusqu'à présent:
d <- merge(d1,d2)
# 7.6 sec
library(plyr)
d <- join(d1,d2)
# 2.9 sec
library(data.table)
dt1 <- data.table(d1, key="x")
dt2 <- data.table(d2, key="x")
d <- data.frame( dt1[dt2,list(x,y1,y2=dt2$y2)] )
# 4.9 sec
library(sqldf)
sqldf()
sqldf("create index ix1 on d1(x)")
sqldf("create index ix2 on d2(x)")
d <- sqldf("select * from d1 inner join d2 on d1.x=d2.x")
sqldf()
# 17.4 sec
performance
r
join
merge
data.table
datasmurf
la source
la source
Réponses:
L'approche de correspondance fonctionne lorsqu'il existe une clé unique dans la deuxième trame de données pour chaque valeur de clé de la première. S'il y a des doublons dans la deuxième trame de données, les approches de correspondance et de fusion ne sont pas les mêmes. Le match est, bien sûr, plus rapide car il n'en fait pas autant. En particulier, il ne recherche jamais de clés en double. (suite après le code)
Dans le code sqldf qui a été publié dans la question, il peut sembler que des index ont été utilisés sur les deux tables mais, en fait, ils sont placés sur des tables qui ont été écrasées avant l'exécution de sql select et qui, en partie, explique pourquoi c'est si lent. L'idée de sqldf est que les trames de données de votre session R constituent la base de données, pas les tables de sqlite. Ainsi, chaque fois que le code fait référence à un nom de table non qualifié, il le recherchera dans votre espace de travail R - pas dans la base de données principale de sqlite. Ainsi, l'instruction select qui a été affichée lit d1 et d2 de l'espace de travail dans la base de données principale de sqlite écrasant celles qui étaient là avec les index. En conséquence, il effectue une jointure sans index. Si vous vouliez utiliser les versions de d1 et d2 qui se trouvaient dans la base de données principale de sqlite, vous devriez les appeler main.d1 et main. d2 et non comme d1 et d2. De plus, si vous essayez de le faire fonctionner aussi vite que possible, notez qu'une simple jointure ne peut pas utiliser les index sur les deux tables afin que vous puissiez gagner du temps pour créer l'un des index. Dans le code ci-dessous, nous illustrons ces points.
Il est intéressant de noter que le calcul précis peut faire une énorme différence sur le package le plus rapide. Par exemple, nous faisons une fusion et un agrégat ci-dessous. On voit que les résultats sont presque inversés pour les deux. Dans le premier exemple, du plus rapide au plus lent, nous obtenons: data.table, plyr, merge et sqldf tandis que dans le second exemple sqldf, aggregate, data.table et plyr - presque l'inverse du premier. Dans le premier exemple, sqldf est 3 fois plus lent que data.table et dans le second, il est 200 fois plus rapide que plyr et 100 fois plus rapide que data.table. Ci-dessous, nous montrons le code d'entrée, les horaires de sortie pour la fusion et les horaires de sortie pour l'agrégat. Il est également intéressant de noter que sqldf est basé sur une base de données et peut donc gérer des objets plus grands que R peut gérer (si vous utilisez l'argument dbname de sqldf) tandis que les autres approches sont limitées au traitement en mémoire principale. Nous avons également illustré sqldf avec sqlite, mais il prend également en charge les bases de données H2 et PostgreSQL.
Les résultats des deux appels de référence comparant les calculs de fusion sont:
Les résultats de l'appel de référence comparant les calculs agrégés sont:
la source
Les 132 secondes rapportées dans les résultats de Gabor
data.table
sont en fait des fonctions de base de synchronisationcolMeans
etcbind
(l'allocation de mémoire et la copie induites par l'utilisation de ces fonctions). Il existe également de bonnes et de mauvaises manières d'utiliserdata.table
.Veuillez noter que je ne connais pas bien le plyr alors veuillez vérifier auprès de Hadley avant de vous fier aux
plyr
horaires ici. Notez également que ledata.table
ne comprend le temps de conversiondata.table
et de définir la clé, pour la farceur.Cette réponse a été mise à jour depuis la réponse initiale en décembre 2010. Les résultats de référence précédents sont indiqués ci-dessous. Veuillez consulter l'historique des révisions de cette réponse pour voir ce qui a changé.
la source
.Internal
appels dans les packages CRAN, voir la politique de référentiel CRAN .data.table
optimise automatiquementmean
maintenant (sans appeler en.Internal
interne).for
boucle, c'est bien. Pourriez-vous ajouter plus d'informations sur "l'analyse SEM" à ce problème? Par exemple, je suppose que SEM = Microscope électronique à balayage? En savoir plus sur l'application la rend plus intéressante pour nous et nous aide à établir des priorités.Pour une tâche simple (valeurs uniques des deux côtés de la jointure), j'utilise
match
:C'est beaucoup plus rapide que la fusion (sur ma machine de 0,13 s à 3,37 s).
Mes horaires:
merge
: 3,32 splyr
: 0,84 smatch
: 0,12 sla source
J'ai pensé qu'il serait intéressant de publier un benchmark avec dplyr dans le mix: (avait beaucoup de choses en cours)
Vient d'ajouter:
et configurez les données pour dplyr avec une table de données:
Actualisé: j'ai supprimé data.tableBad et plyr et rien d'autre que RStudio ouvert (i7, 16 Go de RAM).
Avec data.table 1.9 et dplyr avec data frame:
Avec data.table 1.9 et dplyr avec tableau de données:
Par souci de cohérence, voici l'original avec all et data.table 1.9 et dplyr en utilisant un tableau de données:
Je pense que ces données sont trop petites pour la nouvelle table data.table et déplyr :)
Ensemble de données plus grand:
Il a fallu environ 10 à 13 Go de RAM juste pour contenir les données avant d'exécuter le benchmark.
Résultats:
J'ai essayé un milliard mais j'ai fait sauter le bélier. 32 Go le géreront sans problème.
[Edit by Arun] (dotcomken, pourriez-vous s'il vous plaît exécuter ce code et coller vos résultats d'analyse comparative? Merci).
Selon la demande d'Arun, voici la sortie de ce que vous m'avez fourni pour exécuter:
Désolé pour la confusion, tard dans la nuit m'est arrivé.
L'utilisation de dplyr avec une base de données semble être le moyen le moins efficace de traiter les résumés. Ces méthodes pour comparer la fonctionnalité exacte de data.table et dplyr avec leurs méthodes de structure de données sont-elles incluses? Je préférerais presque séparer cela car la plupart des données devront être nettoyées avant de group_by ou de créer le data.table. Cela peut être une question de goût, mais je pense que le plus important est l'efficacité avec laquelle les données peuvent être modélisées.
la source
En utilisant la fonction de fusion et ses paramètres facultatifs:
Jointure interne: merge (df1, df2) fonctionnera pour ces exemples car R joint automatiquement les cadres par des noms de variables communs, mais vous voudrez probablement spécifier merge (df1, df2, by = "CustomerId") pour vous assurer que vous correspondaient uniquement aux champs souhaités. Vous pouvez également utiliser les paramètres by.x et by.y si les variables correspondantes ont des noms différents dans les différents blocs de données.
la source