web-dev-qa-db-fra.com

Comment effectuer une opération de fusion data.table

note: cette question et les réponses suivantes se réfèrent aux versions de data.table <1.5.3; v. 1.5.3 a été publié en février 2011 pour résoudre ce problème. voir le traitement plus récent (03-2012): Traduire les jointures SQL sur les clés étrangères en syntaxe R data.table


J'ai parcouru la documentation du package data.table (un remplacement de data.frame qui est beaucoup plus efficace pour certaines opérations), y compris Présentation de Josh Reich sur SQL et les données. table au NYC R Meetup (pdf), mais ne peut pas comprendre cette opération totalement triviale.

> x <- DT(a=1:3, b=2:4, key='a')
> x
     a b
[1,] 1 2
[2,] 2 3
[3,] 3 4
> y <- DT(a=1:3, c=c('a','b','c'), key='a')
> y
     a c
[1,] 1 a
[2,] 2 b
[3,] 3 c
> x[y]
     a b
[1,] 1 2
[2,] 2 3
[3,] 3 4
> merge(x,y)
  a b c
1 1 2 a
2 2 3 b
3 3 4 c

Les documents disent "Lorsque [le premier argument] est lui-même un data.table, une jointure est invoquée de la même manière que base :: merge mais utilise une recherche binaire sur la clé triée." Ce n'est clairement pas le cas. Puis-je obtenir les autres colonnes de y dans le résultat de x [y] avec data.tables? Il semble que cela prenne simplement les lignes de x où la clé correspond à la clé de y, mais en ignorant complètement le reste de y ...

49
Harlan

Vous citez la mauvaise partie de la documentation. Si vous regardez le doc de [.data.table vous lirez:

Lorsque i est une table de données, x doit avoir une clé, ce qui signifie joindre i à x et renvoyer les lignes de x qui correspondent . Une équi-jointure est effectuée entre chaque colonne de i et chaque colonne de la clé de x dans l'ordre. Ceci est similaire à la fonctionnalité de base R de sous-paramétrage d'une matrice par une matrice à 2 colonnes, et dans les dimensions supérieures sous-ensemble d'un tableau à n dimensions par une matrice à n colonnes

J'admets que la description du paquet (la partie que vous avez citée) est quelque peu déroutante, car elle semble dire que l'opération "[" peut être utilisée à la place de la fusion. Mais je pense que ce qu'il dit est: si x et y sont tous deux data.tables, nous utilisons une jointure sur un index (qui est invoquée comme fusion) au lieu de la recherche binaire.


Encore une chose:

La bibliothèque data.table que j'ai installée via install.packages manquait le merge.data.table method, donc utiliser merge appeler merge.data.frame. Après avoir installé le paquet de R-Forge R utilisé le plus rapide merge.data.table méthode.

Vous pouvez vérifier si vous disposez de la méthode merge.data.table en vérifiant la sortie de:

methods(generic.function="merge")

EDIT [La réponse n'est plus valide]: Cette réponse fait référence à data.table version 1.3. Dans la version 1.5.3, le comportement de data.table a changé et x [y] renvoie les résultats attendus. Merci Matthew Dowle , auteur de data.table, pour l'avoir signalé dans les commentaires.

29
f3lix

Merci pour les réponses. J'ai raté ce fil lorsqu'il a été initialement publié. data.table a évolué depuis février. La version 1.4.1 a été publiée sur CRAN il y a quelque temps et la version 1.5 est bientôt disponible. Par exemple, l'alias DT () a été remplacé par list (); en tant que primitive, c'est beaucoup plus rapide, et data.table hérite désormais de data.frame donc il fonctionne avec des packages qui niquement acceptent data.frame tels que ggplot et lattice, sans aucune conversion requise (plus rapide et plus pratique ).

Est-il possible de s'abonner à la balise data.table pour que je reçoive un e-mail lorsque quelqu'un poste une question avec cette balise? La liste d'aide datatable est passée à environ 30 à 40 messages par mois, mais je suis heureux de répondre ici aussi si je peux recevoir une sorte de notification.

Matthieu

14
Matt Dowle

Je pense qu'en utilisant le base::merge la fonction n'est pas nécessaire, car l'utilisation de data.table les jointures peuvent être beaucoup plus rapides. Par exemple. voir ce qui suit. Je crée x et y data.tables avec 3-3 colonnes:

x <- data.table( foo = 1:5, a=20:24, Zoo = 5:1 )
y <- data.table( foo = 1:5, b=30:34, boo = 10:14)
setkey(x, foo)
setkey(y, foo)

Et fusionnez les deux avec base:merge et data.table se joint pour voir la vitesse des exécutions:

system.time(merge(x,y))
##    user  system elapsed 
##   0.027   0.000   0.023 

system.time(x[,list(y,x)])
##    user  system elapsed 
##   0.003   0.000   0.006 

Les résultats ne sont pas identiques, car ce dernier a une colonne supplémentaire:

merge(x,y)
##      foo  a Zoo  b boo
## [1,]   1 20   5 30  10
## [2,]   2 21   4 31  11
## [3,]   3 22   3 32  12
## [4,]   4 23   2 33  13
## [5,]   5 24   1 34  14

x[,list(x,y)]
##      foo  a Zoo foo.1  b boo
## [1,]   1 20   5     1 30  10
## [2,]   2 21   4     2 31  11
## [3,]   3 22   3     3 32  12
## [4,]   4 23   2     4 33  13
## [5,]   5 24   1     5 34  14

Ce qui ne pouvait pas faire de gros problèmes :)

11
daroczig

Je pense que f3lix est correct et que la documentation est un peu trompeuse. L'avantage est d'effectuer une jointure rapide pour sous-définir les données. Vous devez finalement utiliser la fonction merge par la suite comme dans votre exemple ci-dessus.

Vous verrez dans la présentation de Josh sur l'utilisation de data.table que c'est ainsi que son exemple fonctionne. Il sous-ensemble d'abord l'un des data.tables, puis fait une fusion:

library(data.table)
sdt <- DT(series, key='series_id')
ddt <- DT(data, key='series_id')
u <- sdt[ grepl('^[A-Z]{2}URN', fred_id) & !grepl('DSURN', fred_id) ]
d <- ddt[ u, DT(min=min(value)), by='series_id', mult='all']
data <- merge(d,series)[,c('title','min','mean','max')]
3
Shane