Recherche…


Introduction

Data.table est un package qui étend les fonctionnalités des trames de données à partir de la base R, améliorant en particulier leurs performances et leur syntaxe. Reportez-vous à la section Docs du package à la rubrique Mise en route avec data.table pour plus de détails.

Syntaxe

  • DT[i, j, by]
    # DT [où, sélectionnez | mettre à jour | faire, par]
  • DT[...][...]
    # chaînage
  • ################# Shortcuts, special functions and special symbols inside DT[...]
  • . ()
    # dans plusieurs arguments, remplace la liste ()
  • J ()
    # en i, remplace la liste ()
  • : =
    # en j, une fonction utilisée pour ajouter ou modifier des colonnes
  • .N
    # dans i, le nombre total de lignes
    # en j, le nombre de lignes d'un groupe
  • .JE
    # en j, le vecteur des numéros de ligne dans le tableau (filtré par i)
  • .DAKOTA DU SUD
    # en j, le sous-ensemble actuel des données
    # sélectionné par l'argument .SDcols
  • .GRP
    # en j, l'index actuel du sous-ensemble des données
  • .PAR
    # en j, la liste des valeurs pour le sous-ensemble de données en cours
  • V1, V2, ...
    # noms par défaut pour les colonnes sans nom créées en j
  • ################# Joins inside DT[...]
  • DT1 [DT2, on, j]
    # joindre deux tables
  • je.*
    # préfixe spécial sur les colonnes de DT2 après la jointure
  • par = .EACHI
    # option spéciale disponible uniquement avec une jointure
  • DT1 [! DT2, on, j]
    # anti-joint deux tables
  • DT1 [DT2, on, roll, j]
    # joindre deux tables, en roulant sur la dernière colonne de on =
  • ################# Reshaping, stacking and splitting
  • faire fondre (DT, id.vars, measure.vars)
    # transformer en format long
    # pour plusieurs colonnes, utilisez measure.vars = patterns (...)
  • dcast (DT, formule)
    # transformer en format large
  • rbind (DT1, DT2, ...)
    # piles énumérées data.tables
  • rbindlist (DT_list, idcol)
    # empile une liste de data.tables
  • split (DT, par)
    # diviser un data.table en une liste
  • ################# Some other functions specialized for data.tables
  • foverlaps
    # chevauchement des jointures
  • fusionner
    # une autre façon de joindre deux tables
  • ensemble
    # autre moyen d'ajouter ou de modifier des colonnes
  • fintersect, fsetdiff, funion, fsetequal, unique, dupliqué, anyDuplicated
    # Opérations de théorie des ensembles avec des lignes en tant qu'éléments
  • uniqueN
    # le nombre de lignes distinctes
  • rowidv (DT, cols)
    # ID de ligne (1 à .N) dans chaque groupe déterminé par les cols
  • rleidv (DT, cols)
    # ID du groupe (1 à .GRP) dans chaque groupe déterminé par des exécutions de cols
  • shift (DT, n, type = c ("lag", "lead"))
    # appliquer un opérateur de décalage à chaque colonne
  • setorder, setcolorder, setnames, setkey, setindex, setattr
    # modifier les attributs et ordonner par référence

Remarques

Installation et support

Pour installer le package data.table:

# install from CRAN
install.packages("data.table")       

# or install development version 
install.packages("data.table", type = "source", repos = "http://Rdatatable.github.io/data.table")

# and to revert from devel to CRAN, the current version must first be removed
remove.packages("data.table")
install.packages("data.table")

Le site officiel du paquet contient des pages wiki pour vous aider à démarrer et des listes de présentations et d'articles du Web. Avant de poser une question - ici sur StackOverflow ou ailleurs - veuillez lire la page de support .

Chargement du paquet

De nombreuses fonctions dans les exemples ci-dessus existent dans l'espace de noms data.table. Pour les utiliser, vous devrez d'abord ajouter une ligne comme la library(data.table) ou utiliser leur chemin complet, comme data.table::fread au lieu de simplement fread . Pour obtenir de l'aide sur des fonctions individuelles, la syntaxe est help("fread") ou ?fread . Encore une fois, si le paquet n'est pas chargé, utilisez le nom complet comme ?data.table::fread .

Créer un data.table

Un data.table est une version améliorée de la classe data.frame de la base R. En tant que tel, son attribut class() est le vecteur "data.table" "data.frame" et les fonctions qui fonctionnent sur un data.frame seront également travailler avec un data.table. Il existe de nombreuses façons de créer, charger ou contraindre un fichier data.table.

Construire

N'oubliez pas d'installer et d'activer le package data.table

library(data.table)

Il y a un constructeur du même nom:

DT <- data.table(
  x = letters[1:5], 
  y = 1:5, 
  z = (1:5) > 3
)
#    x y     z
# 1: a 1 FALSE
# 2: b 2 FALSE
# 3: c 3 FALSE
# 4: d 4  TRUE
# 5: e 5  TRUE

Contrairement à data.frame , data.table ne contraindra pas les chaînes aux facteurs:

sapply(DT, class)
#               x           y           z 
#     "character"   "integer"   "logical" 

Lire dans

Nous pouvons lire un fichier texte:

dt <- fread("my_file.csv")

Contrairement à read.csv , fread lira les chaînes comme des chaînes et non comme des facteurs.

Modifier un data.frame

Pour plus d'efficacité, data.table offre un moyen de modifier un data.frame ou une liste pour créer un fichier data.table (sans faire de copie ni modifier son emplacement de mémoire):

# example data.frame
DF <- data.frame(x = letters[1:5], y = 1:5, z = (1:5) > 3)
# modification
setDT(DF)

Notez que nous ne <- assignons pas le résultat, puisque l'objet DF a été modifié sur place. Les attributs de classe du data.frame seront conservés:

sapply(DF, class)
#         x         y         z 
#  "factor" "integer" "logical" 

Coerce l'objet à data.table

Si vous avez une list , data.frame ou data.table , vous devez utiliser la fonction setDT pour convertir en une data.table car elle effectue la conversion par référence au lieu de faire une copie (ce as.data.table fait as.data.table ). Ceci est important si vous travaillez avec des jeux de données volumineux.

Si vous avez un autre objet R (comme une matrice), vous devez utiliser as.data.table pour le contraindre à une data.table .

mat <- matrix(0, ncol = 10, nrow = 10)

DT <- as.data.table(mat)
# or
DT <- data.table(mat)

Ajout et modification de colonnes

DT[where, select|update|do, by] syntaxe DT[where, select|update|do, by] est utilisée pour travailler avec des colonnes d'un data.table.

  • La partie "where" est l'argument i
  • La partie "select | update | do" est l'argument j

Ces deux arguments sont généralement passés par position plutôt que par nom.

Nos exemples de données ci-dessous sont

mtcars = data.table(mtcars, keep.rownames = TRUE)

Modification de colonnes entières

Utilisez l'opérateur := dans j pour attribuer de nouvelles colonnes:

mtcars[, mpg_sq := mpg^2]

Supprimer les colonnes en définissant la NULL sur NULL :

mtcars[, mpg_sq := NULL]

Ajoutez plusieurs colonnes en utilisant le format multivarié de l'opérateur :=

mtcars[, `:=`(mpg_sq = mpg^2, wt_sqrt = sqrt(wt))]
# or 
mtcars[, c("mpg_sq", "wt_sqrt") := .(mpg^2, sqrt(wt))]

Si les colonnes sont dépendantes et doivent être définies en séquence, une façon est:

mtcars[, c("mpg_sq", "mpg2_hp") := .(temp1 <- mpg^2, temp1/hp)]

La syntaxe .() Est utilisée lorsque le côté droit de LHS := RHS est une liste de colonnes.

Pour les noms de colonnes déterminés dynamiquement, utilisez des parenthèses:

vn = "mpg_sq"
mtcars[, (vn) := mpg^2]

Les colonnes peuvent également être modifiées avec set , bien que cela soit rarement nécessaire:

set(mtcars, j = "hp_over_wt", v = mtcars$hp/mtcars$wt)

Modification de sous-ensembles de colonnes

Utilisez l'argument i pour créer un sous-ensemble des lignes "où" des modifications doivent être apportées:

mtcars[1:3, newvar := "Hello"]
# or
set(mtcars, j = "newvar", i = 1:3, v = "Hello")  

Comme dans un data.frame, nous pouvons sous-utiliser des numéros de lignes ou des tests logiques. Il est également possible d'utiliser une "jointure" dans i , mais cette tâche plus complexe est abordée dans un autre exemple.

Modification des attributs de colonne

Les fonctions qui modifient des attributs, tels que les levels<- ou les names<- , remplacent en réalité un objet par une copie modifiée. Même s'il n'est utilisé que sur une colonne d'un data.table, l'objet entier est copié et remplacé.

Pour modifier un objet sans copie, utilisez setnames pour modifier les noms de colonne d'un data.table ou data.frame et setattr pour modifier un attribut pour n'importe quel objet.

# Print a message to the console whenever the data.table is copied
tracemem(mtcars)
mtcars[, cyl2 := factor(cyl)]

# Neither of these statements copy the data.table
setnames(mtcars, old = "cyl2", new = "cyl_fac")
setattr(mtcars$cyl_fac, "levels", c("four", "six", "eight"))

# Each of these statements copies the data.table
names(mtcars)[names(mtcars) == "cyl_fac"] <- "cf"
levels(mtcars$cf) <- c("IV", "VI", "VIII")

Sachez que ces modifications sont faites par référence, elles sont donc globales . Les modifier dans un environnement affecte l'objet dans tous les environnements.

# This function also changes the levels in the global environment
edit_levels <- function(x) setattr(x, "levels", c("low", "med", "high"))
edit_levels(mtcars$cyl_factor)

Symboles spéciaux dans data.table

.DAKOTA DU SUD

.SD fait référence au sous-ensemble de data.table pour chaque groupe, à l'exclusion de toutes les colonnes utilisées by .

.SD avec lapply peut être utilisé pour appliquer n'importe quelle fonction à plusieurs colonnes par groupe dans un data.table

Nous continuerons à utiliser le même jeu de données mtcars , mtcars :

mtcars = data.table(mtcars) # Let's not include rownames to keep things simpler

Moyenne de toutes les colonnes du jeu de données par nombre de cylindres , cyl :

mtcars[ , lapply(.SD, mean), by = cyl]

#   cyl      mpg     disp        hp     drat       wt     qsec        vs        am     gear     carb
#1:   6 19.74286 183.3143 122.28571 3.585714 3.117143 17.97714 0.5714286 0.4285714 3.857143 3.428571
#2:   4 26.66364 105.1364  82.63636 4.070909 2.285727 19.13727 0.9090909 0.7272727 4.090909 1.545455
#3:   8 15.10000 353.1000 209.21429 3.229286 3.999214 16.77214 0.0000000 0.1428571 3.285714 3.500000

En dehors de cyl , il existe d'autres colonnes catégoriques dans le jeu de données, telles que vs , am , gear et carb . Cela n'a pas vraiment de sens de prendre la mean de ces colonnes. Excluons donc ces colonnes. C'est ici que .SDcols entre en jeu.

.SDcols

.SDcols spécifie les colonnes de data.table incluses dans .SD .

Moyenne de toutes les colonnes (colonnes continues) dans l'ensemble de données selon le nombre d'engrenages gear , et le nombre de cylindres, cyl , disposés par gear et cyl :

# All the continuous variables in the dataset
cols_chosen <- c("mpg", "disp", "hp", "drat", "wt", "qsec")

mtcars[order(gear, cyl), lapply(.SD, mean), by = .(gear, cyl), .SDcols = cols_chosen]

#   gear cyl    mpg     disp       hp     drat       wt    qsec
#1:    3   4 21.500 120.1000  97.0000 3.700000 2.465000 20.0100
#2:    3   6 19.750 241.5000 107.5000 2.920000 3.337500 19.8300
#3:    3   8 15.050 357.6167 194.1667 3.120833 4.104083 17.1425
#4:    4   4 26.925 102.6250  76.0000 4.110000 2.378125 19.6125
#5:    4   6 19.750 163.8000 116.5000 3.910000 3.093750 17.6700
#6:    5   4 28.200 107.7000 102.0000 4.100000 1.826500 16.8000
#7:    5   6 19.700 145.0000 175.0000 3.620000 2.770000 15.5000
#8:    5   8 15.400 326.0000 299.5000 3.880000 3.370000 14.5500

Peut-être que nous ne voulons pas calculer la mean par groupes. Pour calculer la moyenne de toutes les voitures du jeu de données, nous ne spécifions pas la variable by .

mtcars[ , lapply(.SD, mean), .SDcols = cols_chosen] 

#        mpg     disp       hp     drat      wt     qsec
#1: 20.09062 230.7219 146.6875 3.596563 3.21725 17.84875

Remarque:

  • Il n'est pas nécessaire de définir cols_chosen au préalable. .SDcols peut directement prendre des noms de colonnes
  • .SDcols peut également prendre directement un vecteur de colonnes. Dans l'exemple ci-dessus, il s'agirait de mtcars[ , lapply(.SD, mean), .SDcols = c(1,3:7)]

.N

.N est un raccourci pour le nombre de lignes d'un groupe.

iris[, .(count=.N), by=Species]

#      Species count
#1:     setosa    50
#2: versicolor    50
#3:  virginica    50

Ecriture de code compatible à la fois avec data.frame et data.table

Différences dans la syntaxe de sous-ensemble

Une data.table est l'une des structures de données bidimensionnelles disponibles dans R, outre data.frame , matrix et (2D) array . Toutes ces classes utilisent une syntaxe très similaire mais pas identique pour le sous-ensemble, le schéma A[rows, cols] .

Considérons les données suivantes stockées dans une matrix , un data.frame et un data.table :

ma <- matrix(rnorm(12), nrow=4, dimnames=list(letters[1:4], c('X', 'Y', 'Z')))
df <- as.data.frame(ma)
dt <- as.data.table(ma)

ma[2:3]  #---> returns the 2nd and 3rd items, as if 'ma' were a vector (because it is!)
df[2:3]  #---> returns the 2nd and 3rd columns
dt[2:3]  #---> returns the 2nd and 3rd rows!

Si vous voulez être sûr de ce qui sera retourné, il vaut mieux être explicite .

Pour obtenir des lignes spécifiques, ajoutez simplement une virgule après la plage:

ma[2:3, ]  # \
df[2:3, ]  #  }---> returns the 2nd and 3rd rows
dt[2:3, ]  # /

Toutefois, si vous souhaitez créer des sous-ensembles de colonnes , certains cas sont interprétés différemment. Tous les trois peuvent être regroupés de la même manière avec des index entiers ou de caractères non stockés dans une variable.

ma[, 2:3]          #  \
df[, 2:3]          #   \
dt[, 2:3]          #    }---> returns the 2nd and 3rd columns
ma[, c("Y", "Z")]  #   /
df[, c("Y", "Z")]  #  /
dt[, c("Y", "Z")]  # /

Cependant, ils diffèrent pour les noms de variables non cotés

mycols <- 2:3
ma[, mycols]                # \
df[, mycols]                #  }---> returns the 2nd and 3rd columns
dt[, mycols, with = FALSE]  # /

dt[, mycols]                # ---> Raises an error

Dans le dernier cas, mycols est évalué en tant que nom d'une colonne. Comme dt ne peut pas trouver une colonne nommée mycols , une erreur est mycols .

Remarque: Pour les versions du package data.table 1.9.8, ce comportement était légèrement différent. Tout élément de l'index de la colonne aurait été évalué en utilisant dt comme environnement. Donc, dt[, 2:3] et dt[, mycols] renverraient le vecteur 2:3 . Aucune erreur ne serait soulevée pour le second cas, car la variable mycols existe dans l'environnement parent.

Stratégies pour maintenir la compatibilité avec data.frame et data.table

Il existe de nombreuses raisons d'écrire du code qui est garanti pour fonctionner avec data.frame et data.table . Vous êtes peut-être obligé d'utiliser data.frame , ou vous devrez peut-être partager un code que vous ne savez pas comment utiliser. Il existe donc des stratégies principales pour y parvenir, par ordre de commodité:

  1. Utilisez la syntaxe qui se comporte de la même manière pour les deux classes.
  2. Utilisez une fonction commune qui fait la même chose que la syntaxe la plus courte.
  3. Forcer data.table à se comporter comme data.frame (ex .: appeler la méthode spécifique print.data.frame ).
  4. Traitez-les comme une list , ce qu'ils sont finalement.
  5. Convertissez la table en data.frame avant de faire quoi que ce soit (mauvaise idée si c'est une énorme table).
  6. Convertissez la table en data.table , si les dépendances ne sont pas un problème.

Sous-ensembles de lignes. C'est simple, utilisez simplement le sélecteur [, ] , avec la virgule:

A[1:10, ]
A[A$var > 17, ]  # A[var > 17, ] just works for data.table

Colonne de sous-ensemble. Si vous voulez une seule colonne, utilisez le sélecteur $ ou [[ ]] :

A$var
colname <- 'var'
A[[colname]]
A[[1]]

Si vous voulez une méthode uniforme pour saisir plus d’une colonne, il faut faire appel à un peu:

B <- `[.data.frame`(A, 2:4)

# We can give it a better name
select <- `[.data.frame`
B <- select(A, 2:4)
C <- select(A, c('foo', 'bar'))

Sous-ensemble 'lignes indexées'. Alors que data.frame possède row.names , data.table a sa fonctionnalité de key unique. Le mieux est d'éviter complètement les row.names et de tirer parti des optimisations existantes dans le cas de data.table lorsque cela est possible.

B <- A[A$var != 0, ]
# or...
B <- with(A, A[var != 0, ])  # data.table will silently index A by var before subsetting

stuff <- c('a', 'c', 'f')
C <- A[match(stuff, A$name), ]  # really worse than: setkey(A); A[stuff, ]

Obtenez un tableau à 1 colonne, obtenez une ligne en tant que vecteur. Ce sont faciles avec ce que nous avons vu jusqu'à maintenant:

B <- select(A, 2)    #---> a table with just the second column
C <- unlist(A[1, ])  #---> the first row as a vector (coerced if necessary)

Définition des clés dans data.table

Oui, vous devez SETKEY avant 1.9.6

Auparavant (avant 1.9.6), votre data.table était accélérée en définissant des colonnes comme clés de la table, en particulier pour les grandes tables. [Voir la vignette d'introduction page 5 de la version de septembre 2015, où la vitesse de recherche était 544 fois meilleure.]

library(data.table)
DT <- data.table(
  x = letters[1:5], 
  y = 5:1, 
  z = (1:5) > 3
)

#> DT
#   x y     z
#1: a 5 FALSE
#2: b 4 FALSE
#3: c 3 FALSE
#4: d 2  TRUE
#5: e 1  TRUE

Définissez votre clé avec la commande setkey . Vous pouvez avoir une clé avec plusieurs colonnes.

setkey(DT, y)

Vérifiez la clé de votre table dans les tableaux ()

tables()

> tables()
     NAME NROW NCOL MB COLS  KEY
[1,] DT      5    3  1 x,y,z y  
Total: 1MB

Notez que cela reclassera vos données.

#> DT
#   x y     z
#1: e 1  TRUE
#2: d 2  TRUE
#3: c 3 FALSE
#4: b 4 FALSE
#5: a 5 FALSE

Maintenant c'est inutile

Avant la v1.9.6, il fallait définir une clé pour certaines opérations, en particulier pour joindre des tables. Les développeurs de data.table ont accéléré et introduit une fonctionnalité "on=" qui peut remplacer la dépendance aux clés. Voir SO répondre ici pour une discussion détaillée.

En janvier 2017, les développeurs ont écrit une vignette autour des indices secondaires qui explique la syntaxe "on" et permet d'identifier d'autres colonnes pour une indexation rapide.

Créer des indices secondaires?

De manière similaire à key, vous pouvez setindex(DT, key.col) ou setindexv(DT, "key.col.string") , où DT est votre data.table. Supprimez tous les index avec setindex(DT, NULL) .

Voir vos indices secondaires avec des indices(DT) .

Pourquoi des indices secondaires?

Cela ne trie pas la table (contrairement à key), mais permet une indexation rapide en utilisant la syntaxe "on". Notez qu'il ne peut y avoir qu'une seule clé, mais vous pouvez utiliser plusieurs index secondaires, ce qui évite de devoir ressaisir et utiliser la table. Cela accélérera votre sous-ensemble lors de la modification des colonnes sur lesquelles vous souhaitez créer un sous-ensemble.

Rappel, dans l'exemple ci-dessus, y était la clé pour la table DT:

DT
# x y     z
# 1: e 1  TRUE
# 2: d 2  TRUE
# 3: c 3 FALSE
# 4: b 4 FALSE
# 5: a 5 FALSE

# Let us set x as index 
setindex(DT, x)

# Use indices to see what has been set
indices(DT)
# [1] "x"

# fast subset using index and not keyed column
DT["c", on ="x"]
#x y     z
#1: c 3 FALSE

# old way would have been rekeying DT from y to x, doing subset and 
# perhaps keying back to y (now we save two sorts)
# This is a toy example above but would have been more valuable with big data sets


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow