require(data.table) # <-- Au préalable install.packages("data.table")10 Data Tables
Le package data.table a été conçu pour dépasser les limites des dataframes traditionnels, notamment dans le cadre de calculs intensifs ou de la manipulation de très grands volumes de données. Il est souvent préféré au tidyverse pour sa rapidité d’exécution, son efficacité en mémoire et sa syntaxe concise.
Ce que nous allons explorer constitue une première approche des bases. Pour aller plus loin et découvrir toutes les fonctionnalités de data.table, vous pouvez consulter la documentation officielle : https://rdatatable.gitlab.io/data.table.
10.1 Mise en route
La première étape pour utiliser data.table consiste à le charger
Nous allons ici poursuivre avec le même jeu de données que précédemment :
Taille <- c(167, 192, 173, 174, 172, 167, 171, 185, 163, 170)
Poids <- c(86, 74, 83, 50, 78, 66, 66, 51, 50, 55)
Prog <- c("Bac", "Bac", "Master", "Bac", "Bac", "Master", "Master", NA, "Bac", "Bac")
Sexe <- c("H", "H", "F", "H", "H", "H", "F", "H", "H", "H") |> factor()
df <- data.frame(Taille, Poids, Prog, Sexe)Pour utiliser le package data.table, il faut d’abord convertir le dataframe df en un objet datatable à l’aide de la fonction as.data.table() :
dt <- as.data.table(df)
dt Taille Poids Prog Sexe
<num> <num> <char> <fctr>
1: 167 86 Bac H
2: 192 74 Bac H
3: 173 83 Master F
4: 174 50 Bac H
5: 172 78 Bac H
6: 167 66 Master H
7: 171 66 Master F
8: 185 51 <NA> H
9: 163 50 Bac H
10: 170 55 Bac H
str(dt)Classes 'data.table' and 'data.frame': 10 obs. of 4 variables:
$ Taille: num 167 192 173 174 172 167 171 185 163 170
$ Poids : num 86 74 83 50 78 66 66 51 50 55
$ Prog : chr "Bac" "Bac" "Master" "Bac" ...
$ Sexe : Factor w/ 2 levels "F","H": 2 2 1 2 2 2 1 2 2 2
- attr(*, ".internal.selfref")=<externalptr>
L’opération inverse — repasser d’une datatable à une dataframe classique — se fait simplement avec as.data.frame() :
df <- as.data.frame(dt)Il est évidement possible de créer directement une datatable sans passer par un dataframe. Exemple :
dt <- data.table(Taille, Poids, Prog, Sexe)
# ou
dt <- data.table(
Taille = c(167, 192, 173, 174, 172, 167, 171, 185, 163, 170),
Poids = c(86, 74, 83, 50, 78, 66, 66, 51, 50, 55),
Prog = c("Bac", "Bac", "Master", "Bac", "Bac", "Master", "Master", NA, "Bac", "Bac"),
Sexe = c("H", "H", "F", "H", "H", "H", "F", "H", "H", "H") |> factor()
)10.2 Syntaxe générale
La fonctionnement centrale du package data.table repose sur l’utilisation des crochets [...]. Dans un dataframe classique, ces crochets servent uniquement à sélectionner des lignes ou des colonnes. En revanche, appliqués à une datatable, ils permettent d’effectuer une large gamme d’opérations — filtrage, sélection, transformation, agrégation, création de variables — le tout dans une syntaxe compacte et performante. En pratique, presque toutes les manipulations courantes peuvent être réalisées directement à l’aide du syntaxe dt[...].
La forme générale de la syntaxe data.table est donnée par :
dt[i, j, by]Cela peut se lire comme : “sur les lignes en i, j’applique les opérations en j, en regroupant par by”, où :
i: lignes à sélectionner (par numéro ou condition logique)j: opérations à effectuer (sélection, calcul, transformation, etc)by: groupes sur lesquels appliquerj.
Il est utile de noter qu’il n’est pas nécessaire d’utiliser le symbole $ à l’intérieur des crochets [...], ce qui permet d’écrire un code bien plus lisible.
10.3 Sélectionner des lignes
Par numéro/position
dt[c(2, 3)] # Sélectionner les lignes 2 et 3
dt[c(2, 3), ] # Idem
dt[c(2, 3), , ] # Idem
dt[-(4:10), ] # Exclure les lignes de 4 à 10Output
Taille Poids Prog Sexe
<num> <num> <char> <fctr>
1: 192 74 Bac H
2: 173 83 Master F
Taille Poids Prog Sexe
<num> <num> <char> <fctr>
1: 192 74 Bac H
2: 173 83 Master F
Taille Poids Prog Sexe
<num> <num> <char> <fctr>
1: 192 74 Bac H
2: 173 83 Master F
Taille Poids Prog Sexe
<num> <num> <char> <fctr>
1: 167 86 Bac H
2: 192 74 Bac H
3: 173 83 Master F
Par condition logique (filtrage)
dt[Sexe == "H"] # Tous les hommes
dt[Poids > median(Poids)] # Individus avec un poids supérieur à la médiane
dt[Sexe == "H" & Poids > median(Poids)] # Hommes avec poids > médianeOutput
Taille Poids Prog Sexe
<num> <num> <char> <fctr>
1: 167 86 Bac H
2: 192 74 Bac H
3: 174 50 Bac H
4: 172 78 Bac H
5: 167 66 Master H
6: 185 51 <NA> H
7: 163 50 Bac H
8: 170 55 Bac H
Taille Poids Prog Sexe
<num> <num> <char> <fctr>
1: 167 86 Bac H
2: 192 74 Bac H
3: 173 83 Master F
4: 172 78 Bac H
Taille Poids Prog Sexe
<num> <num> <char> <fctr>
1: 167 86 Bac H
2: 192 74 Bac H
3: 172 78 Bac H
Quand on écrit dt[i], cela ne modifie pas l’objet dt. Cette syntaxe crée une copie temporaire contenant uniquement les lignes qui satisfont la condition i. Pour conserver cette sélection, il faut la réassigner à un nouvel objet ou à dt lui-même.
La composent i peut aussi etre utliser pour trier une datatable. Exemple :
# Trie par Taille croissante, puis Prog croissant
dt[order(Taille, Prog)]
# Trie par Taille croissante, puis par Prog décroissant (le signe - inverse l'ordre)
dt[order(Taille, -Prog)]Output
Taille Poids Prog Sexe
<num> <num> <char> <fctr>
1: 163 50 Bac H
2: 167 86 Bac H
3: 167 66 Master H
4: 170 55 Bac H
5: 171 66 Master F
6: 172 78 Bac H
7: 173 83 Master F
8: 174 50 Bac H
9: 185 51 <NA> H
10: 192 74 Bac H
Taille Poids Prog Sexe
<num> <num> <char> <fctr>
1: 163 50 Bac H
2: 167 66 Master H
3: 167 86 Bac H
4: 170 55 Bac H
5: 171 66 Master F
6: 172 78 Bac H
7: 173 83 Master F
8: 174 50 Bac H
9: 185 51 <NA> H
10: 192 74 Bac H
10.4 Sélectionner des colonnes
Par numéro/position
dt[, c(2, 3)] # Colonnes 2 et 3
dt[, -c(2, 3)] # Toutes sauf les colonnes 2 et 3Output
Poids Prog
<num> <char>
1: 86 Bac
2: 74 Bac
3: 83 Master
4: 50 Bac
5: 78 Bac
6: 66 Master
7: 66 Master
8: 51 <NA>
9: 50 Bac
10: 55 Bac
Taille Sexe
<num> <fctr>
1: 167 H
2: 192 H
3: 173 F
4: 174 H
5: 172 H
6: 167 H
7: 171 F
8: 185 H
9: 163 H
10: 170 H
Par nom
dt[, Poids] # Colonne Poids (résultat = vecteur)
dt[, .(Poids)] # Idem (résultat = datatable)
dt[, c("Poids", "Prog")] # Plusieurs colonnes
dt[, .(Poids, Prog)] # Idem (Syntaxe recommandée)
dt[, -c("Poids", "Prog")] # Exclusion par nomOutput
[1] 86 74 83 50 78 66 66 51 50 55
Poids
<num>
1: 86
2: 74
3: 83
4: 50
5: 78
6: 66
7: 66
8: 51
9: 50
10: 55
Poids Prog
<num> <char>
1: 86 Bac
2: 74 Bac
3: 83 Master
4: 50 Bac
5: 78 Bac
6: 66 Master
7: 66 Master
8: 51 <NA>
9: 50 Bac
10: 55 Bac
Poids Prog
<num> <char>
1: 86 Bac
2: 74 Bac
3: 83 Master
4: 50 Bac
5: 78 Bac
6: 66 Master
7: 66 Master
8: 51 <NA>
9: 50 Bac
10: 55 Bac
Taille Sexe
<num> <fctr>
1: 167 H
2: 192 H
3: 173 F
4: 174 H
5: 172 H
6: 167 H
7: 171 F
8: 185 H
9: 163 H
10: 170 H
On peut évidemment combiner les deux opérations, càd sélectionner simultanément certaines lignes et certaines colonnes. Exemple :
# Poids des individus 2 et 3
dt[c(2, 3), .(Poids)]
# Tailles des hommes dont le poids est supérieur à la médiane
dt[Sexe == "H" & Poids > median(Poids), .(Taille)]
# Poids et Prog des hommes
dt[Sexe == "H", .(Poids, Prog)]Output
Poids
<num>
1: 74
2: 83
Taille
<num>
1: 167
2: 192
3: 172
Poids Prog
<num> <char>
1: 86 Bac
2: 74 Bac
3: 50 Bac
4: 78 Bac
5: 66 Master
6: 51 <NA>
7: 50 Bac
8: 55 Bac
10.5 Transformer des colonnes
La composante j d’une datatable ne sert pas uniquement à sélectionner des colonnes, mais permet aussi, contrairement aux dataframes classiques, d’effectuer des calculs sur celles-ci.
Une seule colonne :
On peut créer de nouvelles variables ou de transformer celles existantes via l’opérateur :=. Exemple :
dt[, V := 1:10] # Ajout de la colonne V
dt[, Prog := factor(Prog)] # Transformer Prog en facteur
dt Taille Poids Prog Sexe V
<num> <num> <fctr> <fctr> <int>
1: 167 86 Bac H 1
2: 192 74 Bac H 2
3: 173 83 Master F 3
4: 174 50 Bac H 4
5: 172 78 Bac H 5
6: 167 66 Master H 6
7: 171 66 Master F 7
8: 185 51 <NA> H 8
9: 163 50 Bac H 9
10: 170 55 Bac H 10
Contrairement à transform() ou dplyr::mutate(), qui retournent une copie modifiée du tableau, l’opérateur := de data.table modifie directement les données en mémoire, sans créer de copie intermédiaire. := ne renvoie aucun résultat, mais agit par référence directement sur l’objet original. Les changements sont donc permanents, sans qu’il soit nécessaire de réassigner le tableau. Cette approche est beaucoup plus rapide et efficace, notamment lorsqu’on manipule de très grands volumes de données.
Voici un autre exemple de l’utilisation de :=
# Ajouter "S = 1" dans les lignes où Poids > 70
dt[Poids > 70, S := 1]
dt Taille Poids Prog Sexe V S
<num> <num> <fctr> <fctr> <int> <num>
1: 167 86 Bac H 1 1
2: 192 74 Bac H 2 1
3: 173 83 Master F 3 1
4: 174 50 Bac H 4 NA
5: 172 78 Bac H 5 1
6: 167 66 Master H 6 NA
7: 171 66 Master F 7 NA
8: 185 51 <NA> H 8 NA
9: 163 50 Bac H 9 NA
10: 170 55 Bac H 10 NA
Plusieurs colonnes :
Pour affecter plusieurs colonnes à la fois, on utilise la syntaxe ':='(...). Exemple :
# Suppression + modification + création d'une nouvelle variable
dt[, ":="(
S = NULL,
V = -V,
imc = Poids / (0.01 * Taille)^2
)]
dt Taille Poids Prog Sexe V imc
<num> <num> <fctr> <fctr> <int> <num>
1: 167 86 Bac H -1 30.83653
2: 192 74 Bac H -2 20.07378
3: 173 83 Master F -3 27.73230
4: 174 50 Bac H -4 16.51473
5: 172 78 Bac H -5 26.36560
6: 167 66 Master H -6 23.66524
7: 171 66 Master F -7 22.57105
8: 185 51 <NA> H -8 14.90139
9: 163 50 Bac H -9 18.81892
10: 170 55 Bac H -10 19.03114
Les affectations multiples avec := sont évaluées simultanément, et non de manière séquentielle. Cela a pour conséquence qu’une variable nouvellement créée ne peut pas être utilisée immédiatement dans le calcul d’une autre au sein de la même instruction. Par exemple, le code suivant provoque une erreur :
dt[, ":="(
S = 1,
LS = log(S)
)]Error in eval(jsub, SDenv, parent.frame()): object 'S' not found
10.6 Calculs et résumés sur les colonnes
Dans la composante j d’une datatable, il est possible d’utiliser toute expression R valide : calculs, affichages, graphiques, etc. Habituellement, on y place une seule instruction, mais si l’on souhaite en exécuter plusieurs à la suite, il faut les regrouper dans un bloc de code entouré d’accolades {}. Exemple :
dt[, {
plot(Poids ~ Taille) # Trace un graphique de Poids en fonction de Taille
Poids + Taille # La somme des colonnes Poids et Taille
}] [1] 253 266 256 224 250 233 237 236 213 225
Statistiques simples
# Moyenne de Poids
dt[, mean(Poids)]
# Moyenne et Poids et Taille
dt[, .(moyP = mean(Poids), moyT = mean(Taille))]
# Idem en utilisant la fontion lapply
1dt[, lapply(.(moyP = Poids, moyT = Taille), mean)]- 1
-
La fonction
lapply()fait partie de R de base. Elle permet d’appliquer une fonction (commemean()) à chaque élément d’une liste ou d’un vecteur. Cette notion sera approfondie dans la partie dédiée à la programmation.
[1] 65.9
moyP moyT
<num> <num>
1: 65.9 173.4
moyP moyT
<num> <num>
1: 65.9 173.4
Statistiques agrégées via by
# Version 1 : Moyenne du poids par Sexe et Programme
dt[, .(mean = mean(Poids)), by = .(Sexe, Prog)] Sexe Prog mean
<fctr> <fctr> <num>
1: H Bac 65.5
2: F Master 74.5
3: H Master 66.0
4: H <NA> 51.0
# Version 2 : Ajouter une colonne 'mean' contenant la moyenne du poids par sexe et programme
dt[, mean := mean(Poids), by = .(Sexe, Prog)]
dt Taille Poids Prog Sexe V imc mean
<num> <num> <fctr> <fctr> <int> <num> <num>
1: 167 86 Bac H -1 30.83653 65.5
2: 192 74 Bac H -2 20.07378 65.5
3: 173 83 Master F -3 27.73230 74.5
4: 174 50 Bac H -4 16.51473 65.5
5: 172 78 Bac H -5 26.36560 65.5
6: 167 66 Master H -6 23.66524 66.0
7: 171 66 Master F -7 22.57105 74.5
8: 185 51 <NA> H -8 14.90139 51.0
9: 163 50 Bac H -9 18.81892 65.5
10: 170 55 Bac H -10 19.03114 65.5
Dans by on peut aussi fournir une ou plusieurs conditions logiques. Exemple :
dt[, .(mean = mean(Poids)), by = (Pplus <- Poids > median(Poids))] Pplus mean
<lgcl> <num>
1: TRUE 80.25000
2: FALSE 56.33333
10.7 Mots clés spéciaux de data.table
data.table met à disposition des mots clés spéciaux, appelés variables internes, utilisables à l’intérieur des crochets, qui facilitent les calculs et manipulations des données.
Par exemple, .N est une variable spéciale de data.table qui indique le nombre de lignes dans le tableau, ou dans chaque groupe lorsqu’un regroupement est effectué avec by. Exemple :
# Nombre total de lignes dans dt
dt[, .N]
# Dernière ligne
dt[.N]
# Lignes de la 8e à la dernière
dt[8:.N]
# Nombre de lignes par groupe de Sexe
dt[, .N, by = Sexe]
# Moyenne du Poids et effectif par combinaison de Sexe et Prog
dt[, .(mean = mean(Poids), effectif = .N), by = .(Sexe, Prog)][1] 10
Taille Poids Prog Sexe V imc mean
<num> <num> <fctr> <fctr> <int> <num> <num>
1: 170 55 Bac H -10 19.03114 65.5
Taille Poids Prog Sexe V imc mean
<num> <num> <fctr> <fctr> <int> <num> <num>
1: 185 51 <NA> H -8 14.90139 51.0
2: 163 50 Bac H -9 18.81892 65.5
3: 170 55 Bac H -10 19.03114 65.5
Sexe N
<fctr> <int>
1: H 8
2: F 2
Sexe Prog mean effectif
<fctr> <fctr> <num> <int>
1: H Bac 65.5 6
2: F Master 74.5 2
3: H Master 66.0 1
4: H <NA> 51.0 1
Une autre varaible interne fort utile est .SD souvant utlisée avec .SDcols. “SD” signifie “Subset of Data”. Par défaut, .SD contient toutes les colonnes à l’exception de celles dans by ou celles modifiées ou créées avec avec :=. .SDcols permet de spécifier explicitement quelles colonnes doivent être incluses dans .SD. Exemple :
# Toutes les colonnes
dt[, .SD] Taille Poids Prog Sexe V imc mean
<num> <num> <fctr> <fctr> <int> <num> <num>
1: 167 86 Bac H -1 30.83653 65.5
2: 192 74 Bac H -2 20.07378 65.5
3: 173 83 Master F -3 27.73230 74.5
4: 174 50 Bac H -4 16.51473 65.5
5: 172 78 Bac H -5 26.36560 65.5
6: 167 66 Master H -6 23.66524 66.0
7: 171 66 Master F -7 22.57105 74.5
8: 185 51 <NA> H -8 14.90139 51.0
9: 163 50 Bac H -9 18.81892 65.5
10: 170 55 Bac H -10 19.03114 65.5
# Sous-ensemble ciblé : Taille et Poids
dt[, .SD, .SDcols = c("Taille", "Poids")] Taille Poids
<num> <num>
1: 167 86
2: 192 74
3: 173 83
4: 174 50
5: 172 78
6: 167 66
7: 171 66
8: 185 51
9: 163 50
10: 170 55
Ces deux exemples sont donnés à titre purement illustratif et pédagogique. L’intérêt de .SD apparaît vraiment lorsqu’on souhaite appliquer des opérations sur plusieurs colonnes. Exemple :
# Moyenne de Taille et Poids
dt[, lapply(.SD, mean), .SDcols = c("Taille", "Poids")]
# Moyenne de toutes les colonnes numériques
dt[, lapply(.SD, mean), .SDcols = is.numeric]
# Moyenne de Taille et Poids par Sexe
dt[, lapply(.SD, mean), .SDcols = c("Taille", "Poids"), by = Sexe]
# Crée la colonne 'sum' contenant la somme ligne par ligne de Taille et Poids
dt[, sum := rowSums(.SD), .SDcols = c("Taille", "Poids")]
dtOutput
Taille Poids
<num> <num>
1: 173.4 65.9
Taille Poids V imc mean
<num> <num> <num> <num> <num>
1: 173.4 65.9 -5.5 22.05107 65.9
Sexe Taille Poids
<fctr> <num> <num>
1: H 173.75 63.75
2: F 172.00 74.50
Taille Poids Prog Sexe V imc mean sum
<num> <num> <fctr> <fctr> <int> <num> <num> <num>
1: 167 86 Bac H -1 30.83653 65.5 253
2: 192 74 Bac H -2 20.07378 65.5 266
3: 173 83 Master F -3 27.73230 74.5 256
4: 174 50 Bac H -4 16.51473 65.5 224
5: 172 78 Bac H -5 26.36560 65.5 250
6: 167 66 Master H -6 23.66524 66.0 233
7: 171 66 Master F -7 22.57105 74.5 237
8: 185 51 <NA> H -8 14.90139 51.0 236
9: 163 50 Bac H -9 18.81892 65.5 213
10: 170 55 Bac H -10 19.03114 65.5 225
10.8 Enchaîner plusieurs opérations
il est possible d’enchaîner plusieurs opérations en utilisant les crochets [...] les uns après les autres selon la syntaxe :
dt[opération1][opération2][opération3]...Chaque opération dans [] prend la datatable provenant de l’opération précédente et lui applique une nouvelle transformation. Le résultat final est le cumul de toutes ces transformations appliquées séquentiellement. Exemple :
- 1
-
Partir de
dt, filtrer les lignes pour ne garder que les individus dontTailleest supérieure à sa médiane. On ne conserve que les colonnesPoids,ProgetSexe. - 2
-
Partir des données obtenues en (1), calculer le poids moyen par
Sexeet enregistrer le résulta dansmoyP. - 3
-
Partir des données obtenues en (2), trier les lignes par ordre alphabétique de
Sexe.
Sexe moyP
<fctr> <num>
1: F 83.00
2: H 63.25
