data.table
Joint et fusionne
Recherche…
Introduction
?`[.data.table`
pour les documents officiels.
Syntaxe
- x [i, on, j]
# join: data.table x & data.table ou list i - x [! i, on, j]
# anti-jointure
Remarques
Travailler avec des tables à clés
Si x
et i
ont une clé ou que x
est associé aux premières colonnes de i
, alors on
peut ignorer la fonction x[i]
.
Désactiver les noms de colonnes en commun
En j
de x[i, on, j]
, les colonnes de i
peuvent être référencées avec les préfixes i.*
.
Regroupement sur des sous-ensembles
En j
de x[i, on, j, by=.EACHI]
, j
est calculé pour chaque ligne de i
.
C'est la seule valeur de by
vaut la peine. Pour toute autre valeur, les colonnes de i
ne sont pas disponibles.
Mettre à jour les valeurs dans une jointure
Lorsque les données sont "rangées", elles sont souvent organisées en plusieurs tables. Pour combiner les données à analyser, nous devons "mettre à jour" une table avec les valeurs d'une autre.
Par exemple, nous pouvons avoir des données de vente pour les performances, où les attributs de l'exécutant (leur budget) et de l'emplacement (sa population) sont stockés dans des tables séparées:
set.seed(1)
mainDT = data.table(
p_id = rep(LETTERS[1:2], c(2,4)),
geo_id = sample(rep(state.abb[c(1,25,50)], 3:1)),
sales = sample(100, 6)
)
pDT = data.table(id = LETTERS[1:2], budget = c(60, 75))
geoDT = data.table(id = state.abb[c(1,50)], pop = c(100, 200))
mainDT # sales data
# p_id geo_id sales
# 1: A AL 95
# 2: A WY 66
# 3: B AL 62
# 4: B MO 6
# 5: B AL 20
# 6: B MO 17
pDT # performer attributes
# id budget
# 1: A 60
# 2: B 75
geoDT # location attributes
# id pop
# 1: AL 100
# 2: WY 200
Lorsque nous sommes prêts à faire des analyses, nous devons récupérer les variables de ces autres tables:
DT = copy(mainDT)
DT[pDT, on=.(p_id = id), budget := i.budget]
DT[geoDT, on=.(geo_id = id), pop := i.pop]
# p_id geo_id sales budget pop
# 1: A AL 95 60 100
# 2: A WY 66 60 200
# 3: B AL 62 75 100
# 4: B MO 6 75 NA
# 5: B AL 20 75 100
# 6: B MO 17 75 NA
Une copy
est prise pour éviter de contaminer les données brutes, mais nous pourrions travailler directement sur mainDT
place.
Avantages de l'utilisation de tables séparées
Les avantages de cette structure sont traités dans le document sur les données bien rangées, mais dans ce contexte:
Traçage des données manquantes Seules les lignes correspondant à la fusion reçoivent une affectation. Nous n'avons pas de données pour
geo_id == "MO"
ci-dessus, donc ses variables sontNA
dans notre table finale. Si nous voyons des données manquantes comme celle-ci de manière inattendue, nous pouvons remonter à l'observation manquante dans le tableaugeoDT
et rechercher à partir de là si nous avons un problème de données qui peut être résolu.Compréhensibilité. En construisant notre modèle statistique, il peut être important de garder à l’esprit que le
budget
est constant pour chaque interprète. En général, la compréhension de la structure des données porte ses fruits.Taille mémoire. Il peut y avoir un grand nombre d'attributs interprètes et localisés qui ne se retrouvent pas dans le modèle statistique. De cette façon, nous n'avons pas besoin de les inclure dans la table (éventuellement massive) utilisée pour l'analyse.
Détermination par programme des colonnes
S'il y a beaucoup de colonnes dans pDT
, mais que nous voulons seulement en sélectionner quelques-unes, nous pouvons utiliser
p_cols = "budget"
DT[pDT, on=.(p_id = id), (p_cols) := mget(sprintf("i.%s", p_cols))]
Les parenthèses autour de (p_cols) :=
sont essentielles, comme indiqué dans la documentation sur la création de colonnes .
Equi-join
# example data
a = data.table(id = c(1L, 1L, 2L, 3L, NA_integer_), x = 11:15)
# id x
# 1: 1 11
# 2: 1 12
# 3: 2 13
# 4: 3 14
# 5: NA 15
b = data.table(id = 1:2, y = -(1:2))
# id y
# 1: 1 -1
# 2: 2 -2
Intuition
Pensez à x[i]
en sélectionnant un sous-ensemble de x
pour chaque ligne de i
. Cette syntaxe reflète la matrice subsing dans la base R et est cohérente avec le premier argument signifiant "où", dans DT[where, select|update|do, by]
.
On peut se demander pourquoi cette nouvelle syntaxe mérite d’être apprise, puisque la merge(x,i)
fonctionne toujours avec data.tables. La réponse courte est que nous voulons généralement fusionner et ensuite faire quelque chose de plus. La syntaxe x[i]
capture de manière concise ce modèle d'utilisation et permet également un calcul plus efficace. Pour une explication plus détaillée, lisez la FAQ 1.12 et 2.14 .
Gestion des lignes à plusieurs correspondances
Par défaut, chaque ligne d' a
correspondant de chaque ligne b
est renvoyée:
a[b, on="id"]
# id x y
# 1: 1 11 -1
# 2: 1 12 -1
# 3: 2 13 -2
Cela peut être modifié avec mult
:
a[b, on="id", mult="first"]
# id x y
# 1: 1 11 -1
# 2: 2 13 -2
Gestion des lignes sans correspondance
Par défaut, les lignes non appariées d' a
apparaissent dans le résultat:
b[a, on="id"]
# id y x
# 1: 1 -1 11
# 2: 1 -1 12
# 3: 2 -2 13
# 4: 3 NA 14
# 5: NA NA 15
Pour les masquer, utilisez nomatch
:
b[a, on="id", nomatch=0]
# id y x
# 1: 1 -1 11
# 2: 1 -1 12
# 3: 2 -2 13
Notez que x[i]
tentera de faire correspondre les NA dans i
.
Comptage des correspondances renvoyées
Pour compter le nombre de correspondances pour chaque ligne de i
, utilisez .N
et by=.EACHI
.
b[a, on="id", .N, by=.EACHI]
# id N
# 1: 1 1
# 2: 1 1
# 3: 2 1
# 4: 3 0
# 5: NA 0