data.table
Utiliser des clés et des index
Recherche…
Introduction
Remarques
Les vignettes officielles sont la meilleure introduction à ce sujet:
- "Sous-ensemble de clés et de recherche binaire rapide"
- "Indices secondaires et indexation automatique"
Clés vs indices
Une data.table peut être "saisie" par une séquence de colonnes, indiquant aux fonctions intéressées que les données sont triées par ces colonnes. Pour obtenir ou définir la clé, utilisez les fonctions documentées à la ?key
De même, les fonctions peuvent tirer parti des "indices" de data.table. Chaque index - et une table peut en avoir plusieurs - stocke des informations sur l’ordre des données en respectant une séquence de colonnes. Comme une clé, un index peut accélérer certaines tâches. Pour obtenir ou définir des indices, utilisez les fonctions documentées dans ?indices
.
Les indices peuvent également être définis automatiquement (actuellement pour une seule colonne à la fois). Voir ?datatable.optimize
pour plus de détails sur son fonctionnement et sa désactivation si nécessaire.
Vérification et mise à jour
Les valeurs manquantes sont autorisées dans une colonne de clé.
Les clés et les index sont stockés en tant qu'attributs et peuvent, par accident, ne pas correspondre à l'ordre réel des données dans la table. De nombreuses fonctions vérifient la validité de la clé ou de l'index avant de l'utiliser, mais il convient de garder à l'esprit.
Les clés et les index sont supprimés après les mises à jour, où il n'est pas évident que l'ordre de tri est préservé. Par exemple, à partir de DT = data.table(a=c(1,2,4), key="a")
, si nous mettons à jour comme DT[2, a := 3]
, la clé est brisée.
Amélioration des performances pour la sélection des sous-ensembles
# example data
set.seed(1)
n = 1e7
ng = 1e4
DT = data.table(
g1 = sample(ng, n, replace=TRUE),
g2 = sample(ng, n, replace=TRUE),
v = rnorm(n)
)
Correspondance sur une colonne
Après la première exécution d'une opération de sous-ensemble avec ==
ou %in%
...
system.time(
DT[ g1 %in% 1:100]
)
# user system elapsed
# 0.12 0.03 0.16
Un index a été créé automatiquement pour g1
. Les opérations subséquentes de sous-ensembles s'exécutent presque instantanément:
system.time(
DT[ g1 %in% 1:100]
)
# user system elapsed
# 0 0 0
Pour surveiller la création ou l'utilisation d'un index, ajoutez l'option verbose=TRUE
ou modifiez les options(datatable.verbose=TRUE)
paramètres globaux options(datatable.verbose=TRUE)
.
Correspondance sur plusieurs colonnes
Actuellement, la correspondance sur deux colonnes ne crée pas automatiquement un index:
system.time(
DT[ g1 %in% 1:100 & g2 %in% 1:100]
)
# user system elapsed
# 0.57 0.00 0.57
Relancez ceci et il restera lent. Même si nous ajoutons manuellement l'index avec setindex(DT, g1, g2)
, il restera lent car cette requête n'est pas encore optimisée par le package.
Heureusement, si nous pouvons énumérer les combinaisons de valeurs que nous souhaitons rechercher et qu’un index est disponible, nous pouvons rapidement les joindre:
system.time(
DT[ CJ(g1 = 1:100, g2 = 1:100, unique=TRUE), on=.(g1, g2), nomatch=0]
)
# user system elapsed
# 0.53 0.00 0.54
setindex(DT, g1, g2)
system.time(
DT[ CJ(g1 = 1:100, g2 = 1:100, unique=TRUE), on=.(g1, g2), nomatch=0]
)
# user system elapsed
# 0 0 0
Avec CJ
, il est important de faire attention au nombre de combinaisons devenant trop important.