web-dev-qa-db-fra.com

Jointure gauche à l'aide de data.table

Supposons que j'en ai deux data.table:

UNE:

  A  B
1: 1 12
2: 2 13
3: 3 14
4: 4 15

B:

   A  B
1: 2 13
2: 3 14

et j'ai le code suivant:

merge_test = merge(dataA, dataB, by="A", all.data=TRUE)

Je reçois:

   A B.x B.y
1: 2  13  13
2: 3  14  14

Cependant, je veux toutes les lignes de dataA dans la table fusionnée finale. Y a-t-il un moyen de faire cela?

37
lord12

Vous pouvez essayer ceci:

# used data
# set the key in 'B' to the column which you use to join
A <- data.table(a = 1:4, b = 12:15)
B <- data.table(a = 2:3, b = 13:14, key = 'a') 

B[A]
19
danas.zuokas

Si vous souhaitez ajouter les valeurs b de B à A, il est préférable de joindre A avec B et de mettre à jour A par référence comme suit:

A[B, on = 'a', bb := i.b]

qui donne:

> A
   a  b bb
1: 1 12 NA
2: 2 13 13
3: 3 14 14
4: 4 15 NA

Il s'agit d'une meilleure approche que d'utiliser B[A, on='a'] car ce dernier imprime simplement le résultat sur la console. Pour récupérer les résultats dans A, vous devez utiliser A <- B[A, on='a'] qui vous donnera le même résultat.

La raison pour laquelle A[B, on = 'a', bb := i.b] est mieux que A <- B[A, on = 'a'] est l'efficacité de la mémoire. Avec A[B, on = 'a', bb := i.b] l'emplacement de A en mémoire reste le même:

> address(A)
[1] "0x102afa5d0"
> A[B, on = 'a', bb := i.b]
> address(A)
[1] "0x102afa5d0"

Alors que d'autre part avec A <- B[A, on = 'a'], un nouvel objet est créé et enregistré en mémoire sous le nom A et a donc un autre emplacement en mémoire:

> address(A)
[1] "0x102abae50"
> A <- B[A, on = 'a']
> address(A)
[1] "0x102aa7e30"

Utilisation de merge (merge.data.table) entraîne une modification similaire de l'emplacement de la mémoire:

> address(A)
[1] "0x111897e00"
> A <- merge(A, B, by = 'a', all.x = TRUE)
> address(A)
[1] "0x1118ab000"

Pour l'efficacité de la mémoire, il est donc préférable d'utiliser une syntaxe 'mise à jour par référence-join' :

A[B, on = 'a', bb := i.b] 

Bien que cela ne fasse pas de différence notable avec de petits ensembles de données comme ceux-ci, cela fait une différence sur de grands ensembles de données pour lesquels data.table a été conçu.

Il convient également de mentionner que l'ordre de A reste le même.


Pour voir l'effet sur la vitesse et l'utilisation de la mémoire, comparons avec des ensembles de données plus importants (pour les données, voir la 2ème partie des données utilisées - section ci-dessous) :

library(bench)
bm <- mark(AA <- BB[AA, on = .(aa)],
           AA[BB, on = .(aa), cc := cc],
           iterations = 1)

ce qui donne (uniquement les mesures pertinentes indiquées):

> bm[,c(1,3,5)]
# A tibble: 2 x 3
  expression                         median mem_alloc
  <bch:expr>                       <bch:tm> <bch:byt>
1 AA <- BB[AA, on = .(aa)]            4.98s     4.1GB
2 AA[BB, on = .(aa), `:=`(cc, cc)] 560.88ms   384.6MB

Ainsi, dans cette configuration, la 'mise à jour par référence-jointure' est environ 9 fois plus rapide et consomme 11 fois moins de mémoire.

REMARQUE: les gains de vitesse et d'utilisation de la mémoire peuvent différer selon les configurations.


Données utilisées:

# initial datasets
A <- data.table(a = 1:4, b = 12:15)
B <- data.table(a = 2:3, b = 13:14)

# large datasets for the benchmark
set.seed(2019)
AA <- data.table(aa = 1:1e8, bb = sample(12:19, 1e7, TRUE))
BB <- data.table(aa = sample(AA$a, 2e5), cc = sample(2:8, 2e5, TRUE))
92
Jaap