data.table
Remodelage, empilement et fractionnement
Recherche…
Remarques
La vignette officielle, "Réorganisation efficace à l'aide de data.tables" , est la meilleure introduction à ce sujet.
De nombreuses tâches de remodelage nécessitent un déplacement entre des formats longs et larges:
- Les données larges sont des données, chaque colonne représentant une variable distincte et les lignes représentant des observations séparées
- Les données longues sont des données avec le formulaire ID | variable | valeur, où chaque ligne représentant une paire de variables d'observation
fondre et couler avec data.table
data.table
offre un large éventail de possibilités pour remodeler vos données à la fois efficacement et facilement
Par exemple, en remodelant de long en large, vous pouvez à la fois passer plusieurs variables dans le value.var
et les paramètres fun.aggregate
en même temps
library(data.table) #v>=1.9.6
DT <- data.table(mtcars)
Long à large
dcast(DT, gear ~ cyl, value.var = c("disp", "hp"), fun = list(mean, sum))
gear disp_mean_4 disp_mean_6 disp_mean_8 hp_mean_4 hp_mean_6 hp_mean_8 disp_sum_4 disp_sum_6 disp_sum_8 hp_sum_4 hp_sum_6 hp_sum_8
1: 3 120.100 241.5 357.6167 97 107.5 194.1667 120.1 483.0 4291.4 97 215 2330
2: 4 102.625 163.8 NaN 76 116.5 NaN 821.0 655.2 0.0 608 466 0
3: 5 107.700 145.0 326.0000 102 175.0 299.5000 215.4 145.0 652.0 204 175 599
Cela va définir l' gear
comme la colonne d'index, tandis que la mean
et la sum
seront calculées pour disp
et hp
pour chaque combinaison de gear
et cyl
. Si certaines combinaisons n'existent pas, vous pouvez spécifier des paramètres supplémentaires tels que na.rm = TRUE
(qui seront transmis aux fonctions mean
et sum
) ou spécifier l'argument de fill
intégré. Vous pouvez également ajouter des marges, supprimer des combinaisons manquantes et sous-ensemble les données. Voir plus dans ?data.table::dcast
Large à long
Tout en remodelant de long en long, vous pouvez passer des colonnes au paramètre measure.vars
aide d'expressions régulières, par exemple
print(melt(DT, c("cyl", "gear"), measure = patterns("^d", "e")), n = 10)
cyl gear variable value1 value2
1: 6 4 1 160.00 16.46
2: 6 4 1 160.00 17.02
3: 4 4 1 108.00 18.61
4: 6 3 1 258.00 19.44
5: 8 3 1 360.00 17.02
---
60: 4 5 2 3.77 5.00
61: 8 5 2 4.22 5.00
62: 6 5 2 3.62 5.00
63: 8 5 2 3.54 5.00
64: 4 4 2 4.11 4.00
Cela fera melt
les données par cyl
et gear
comme les colonnes d'index, alors que toutes les valeurs pour les variables qui commencent par d
( disp
& drat
) seront présentes dans value1
et les valeurs pour les variables qui contiennent la lettre e
dedans ( qsec
et gear
) seront présents dans la colonne value2
.
Vous pouvez également renommer tous les noms de colonne du résultat en spécifiant variable.name
arguments variable.name
et value.name
ou décider si vous souhaitez que les colonnes de character
soient automatiquement converties en factor
s ou en spécifiant variable.factor
arguments variable.factor
et value.factor
. Voir plus dans ?data.table::melt
Redéfinir en utilisant `data.table`
data.table
étend les reshape2
de melt
et de dcast
( Référence: Remodelage efficace à l'aide de data.tables )
library(data.table)
## generate some data
dt <- data.table(
name = rep(c("firstName", "secondName"), each=4),
numbers = rep(1:4, 2),
value = rnorm(8)
)
dt
# name numbers value
# 1: firstName 1 -0.8551881
# 2: firstName 2 -1.0561946
# 3: firstName 3 0.2671833
# 4: firstName 4 1.0662379
# 5: secondName 1 -0.4771341
# 6: secondName 2 1.2830651
# 7: secondName 3 -0.6989682
# 8: secondName 4 -0.6592184
Long à large
dcast(data = dt,
formula = name ~ numbers,
value.var = "value")
# name 1 2 3 4
# 1: firstName 0.1836433 -0.8356286 1.5952808 0.3295078
# 2: secondName -0.8204684 0.4874291 0.7383247 0.5757814
Sur plusieurs colonnes (à partir de data.table
1.9.6)
## add an extra column
dt[, value2 := value * 2]
## cast multiple value columns
dcast(data = dt,
formula = name ~ numbers,
value.var = c("value", "value2"))
# name value_1 value_2 value_3 value_4 value2_1 value2_2 value2_3 value2_4
# 1: firstName 0.1836433 -0.8356286 1.5952808 0.3295078 0.3672866 -1.6712572 3.190562 0.6590155
# 2: secondName -0.8204684 0.4874291 0.7383247 0.5757814 -1.6409368 0.9748581 1.476649 1.1515627
Large à long
## use a wide data.table
dt <- fread("name 1 2 3 4
firstName 0.1836433 -0.8356286 1.5952808 0.3295078
secondName -0.8204684 0.4874291 0.7383247 0.5757814", header = T)
dt
# name 1 2 3 4
# 1: firstName 0.1836433 -0.8356286 1.5952808 0.3295078
# 2: secondName -0.8204684 0.4874291 0.7383247 0.5757814
## melt to long, specifying the id column, and the name of the columns
## in the resulting long data.table
melt(dt,
id.vars = "name",
variable.name = "numbers",
value.name = "myValue")
# name numbers myValue
# 1: firstName 1 0.1836433
# 2: secondName 1 -0.8204684
# 3: firstName 2 -0.8356286
# 4: secondName 2 0.4874291
# 5: firstName 3 1.5952808
# 6: secondName 3 0.7383247
# 7: firstName 4 0.3295078
# 8: secondName 4 0.5757814
Passer du format large au format long en utilisant la fusion
Fusion: les bases
La fusion est utilisée pour transformer les données du format large au format long.
En commençant par un large ensemble de données:
DT = data.table(ID = letters[1:3], Age = 20:22, OB_A = 1:3, OB_B = 4:6, OB_C = 7:9)
Nous pouvons fondre nos données en utilisant la fonction melt
dans data.table. Cela retourne un autre data.table au format long:
melt(DT, id.vars = c("ID","Age"))
1: a 20 OB_A 1
2: b 21 OB_A 2
3: c 22 OB_A 3
4: a 20 OB_B 4
5: b 21 OB_B 5
6: c 22 OB_B 6
7: a 20 OB_C 7
8: b 21 OB_C 8
9: c 22 OB_C 9
class(melt(DT, id.vars = c("ID","Age")))
# "data.table" "data.frame"
Toutes les colonnes non définies dans le paramètre id.vars
sont supposées être des variables. Alternativement, nous pouvons les définir explicitement à l'aide de l'argument measure.vars
:
melt(DT, measure.vars = c("OB_A","OB_B","OB_C"))
ID Age variable value
1: a 20 OB_A 1
2: b 21 OB_A 2
3: c 22 OB_A 3
4: a 20 OB_B 4
5: b 21 OB_B 5
6: c 22 OB_B 6
7: a 20 OB_C 7
8: b 21 OB_C 8
9: c 22 OB_C 9
Dans ce cas, toutes les colonnes non définies dans measure.vars
sont supposées être des identifiants.
Si nous définissons les deux explicitement, il ne retournera que les colonnes sélectionnées:
melt(DT, id.vars = "ID", measure.vars = c("OB_C"))
ID variable value
1: a OB_C 7
2: b OB_C 8
3: c OB_C 9
Nommer les variables et les valeurs dans le résultat
Nous pouvons manipuler les noms de colonne de la table renvoyée en utilisant variable.name
et value.name
melt(DT,
id.vars = c("ID"),
measure.vars = c("OB_C"),
variable.name = "Test",
value.name = "Result"
)
ID Test Result
1: a OB_C 7
2: b OB_C 8
3: c OB_C 9
Définition des types de variables de mesure dans le résultat
Par défaut, la fusion d’une data.table convertit tous les measure.vars
en facteurs:
M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"))
class(M_DT[, variable])
# "factor"
Pour définir en tant que caractère, utilisez l'argument variable.factor
:
M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"), variable.factor = FALSE)
class(M_DT[, variable])
# "character"
Les valeurs héritent généralement du type de données de la colonne d'origine:
class(DT[, value])
# "integer"
class(M_DT[, value])
# "integer"
En cas de conflit, les types de données seront forcés. Par exemple:
M_DT <- melt(DT,id.vars = c("Age"), measure.vars = c("ID","OB_C"))
class(M_DT[, value])
# "character"
Lors de la fusion, toute variable de facteur sera contrainte au type de caractère:
DT[, OB_C := factor(OB_C)]
M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"))
class(M_DT)
# "character"
Pour éviter cela et conserver la saisie initiale, utilisez l'argument value.factor
:
M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"), value.factor = TRUE)
class(M_DT)
# "factor"
Manipulation des valeurs manquantes
Par défaut, toutes les valeurs NA
sont conservées dans les données fondues
DT = data.table(ID = letters[1:3], Age = 20:22, OB_A = 1:3, OB_B = 4:6, OB_C = c(7:8,NA))
melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"))
ID variable value
1: a OB_C 7
2: b OB_C 8
3: c OB_C NA
Si ceux-ci doivent être supprimés de vos données, définissez na.rm = TRUE
melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"), na.rm = TRUE)
ID variable value
1: a OB_C 7
2: b OB_C 8
Passer du format long au format large en utilisant dcast
Casting: les bases
Le casting est utilisé pour transformer les données du format long au format large.
En commençant par un long ensemble de données:
DT = data.table(ID = rep(letters[1:3],3), Age = rep(20:22,3), Test = rep(c("OB_A","OB_B","OB_C"), each = 3), Result = 1:9)
Nous pouvons dcast
nos données en utilisant la fonction dcast dans data.table. Cela retourne un autre data.table au format large:
dcast(DT, formula = ID ~ Test, value.var = "Result")
ID OB_A OB_B OB_C
1: a 1 4 7
2: b 2 5 8
3: c 3 6 9
class(dcast(DT, formula = ID ~ Test, value.var = "Result"))
[1] "data.table" "data.frame"
Lancer une valeur
Un argument value.var
est nécessaire pour une distribution correcte - si elle n'est pas fournie, Dcast émettra une hypothèse basée sur vos données.
dcast(DT, formula = ID ~ Test, value.var = "Result")
ID OB_A OB_B OB_C
1: a 1 4 7
2: b 2 5 8
3: c 3 6 9
ID OB_A OB_B OB_C
1: a 20 20 20
2: b 21 21 21
3: c 22 22 22
Plusieurs value.var
peuvent être fournies dans une liste
dcast(DT, formula = ID ~ Test, value.var = list("Result","Age"))
ID Result_OB_A Result_OB_B Result_OB_C Age_OB_A Age_OB_B Age_OB_C
1: a 1 4 7 20 20 20
2: b 2 5 8 21 21 21
3: c 3 6 9 22 22 22
Formule
Le casting est contrôlé en utilisant l'argument de la formule dans dcast
. C'est de la forme ROWS ~ COLUMNS
dcast(DT, formula = ID ~ Test, value.var = "Result")
ID OB_A OB_B OB_C
1: a 1 4 7
2: b 2 5 8
3: c 3 6 9
dcast(DT, formula = Test ~ ID, value.var = "Result")
Test a b c
1: OB_A 1 2 3
2: OB_B 4 5 6
3: OB_C 7 8 9
Les lignes et les colonnes peuvent être étendues avec d'autres variables en utilisant +
dcast(DT, formula = ID + Age ~ Test, value.var = "Result")
ID Age OB_A OB_B OB_C
1: a 20 1 4 7
2: b 21 2 5 8
3: c 22 3 6 9
dcast(DT, formula = ID ~ Age + Test, value.var = "Result")
ID 20_OB_A 20_OB_B 20_OB_C 21_OB_A 21_OB_B 21_OB_C 22_OB_A 22_OB_B 22_OB_C
1: a 1 4 7 NA NA NA NA NA NA
2: b NA NA NA 2 5 8 NA NA NA
3: c NA NA NA NA NA NA 3 6 9
#order is important
dcast(DT, formula = ID ~ Test + Age, value.var = "Result")
ID OB_A_20 OB_A_21 OB_A_22 OB_B_20 OB_B_21 OB_B_22 OB_C_20 OB_C_21 OB_C_22
1: a 1 NA NA 4 NA NA 7 NA NA
2: b NA 2 NA NA 5 NA NA 8 NA
3: c NA NA 3 NA NA 6 NA NA 9
Le casting peut souvent créer des cellules où aucune observation n'existe dans les données. Par défaut, cela est désigné par NA
, comme ci-dessus. Nous pouvons remplacer cela par l'argument fill=
.
dcast(DT, formula = ID ~ Test + Age, value.var = "Result", fill = 0)
ID OB_A_20 OB_A_21 OB_A_22 OB_B_20 OB_B_21 OB_B_22 OB_C_20 OB_C_21 OB_C_22
1: a 1 0 0 4 0 0 7 0 0
2: b 0 2 0 0 5 0 0 8 0
3: c 0 0 3 0 0 6 0 0 9
Vous pouvez également utiliser deux variables spéciales dans l'objet formule
-
.
ne représente pas d'autres variables -
...
représente toutes les autres variables
dcast(DT, formula = Age ~ ., value.var = "Result")
Age .
1: 20 3
2: 21 3
3: 22 3
dcast(DT, formula = ID + Age ~ ..., value.var = "Result")
ID Age OB_A OB_B OB_C
1: a 20 1 4 7
2: b 21 2 5 8
3: c 22 3 6 9
Agréger notre value.var
Nous pouvons également couler et agréger les valeurs en une seule étape. Dans ce cas, nous avons trois observations dans chacune des intersections de Age et ID. Pour définir quelle agrégation nous voulons, nous utilisons l'argument fun.aggregate
:
#length
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = length)
ID 20 21 22
1: a 3 0 0
2: b 0 3 0
3: c 0 0 3
#sum
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = sum)
ID 20 21 22
1: a 12 0 0
2: b 0 15 0
3: c 0 0 18
#concatenate
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = function(x){paste(x,collapse = "_")})
ID 20 21 22
1: a 1_4_7
2: b 2_5_8
3: c 3_6_9
On peut aussi passer une liste à fun.aggregate
pour utiliser plusieurs fonctions
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = list(sum,length))
ID Result_sum_20 Result_sum_21 Result_sum_22 Result_length_20 Result_length_21 Result_length_22
1: a 12 0 0 3 0 0
2: b 0 15 0 0 3 0
3: c 0 0 18 0 0 3
Si on passe plus d'une fonction et plus d'une valeur, on peut calculer toutes les combinaisons en passant un vecteur de value.vars
dcast(DT, formula = ID ~ Age, value.var = c("Result","Test"), fun.aggregate = list(function(x){paste0(x,collapse = "_")},length))
ID Result_function_20 Result_function_21 Result_function_22 Test_function_20 Test_function_21 Test_function_22 Result_length_20 Result_length_21
1: a 1_4_7 OB_A_OB_B_OB_C 3 0
2: b 2_5_8 OB_A_OB_B_OB_C 0 3
3: c 3_6_9 OB_A_OB_B_OB_C 0 0
Result_length_22 Test_length_20 Test_length_21 Test_length_22
1: 0 3 0 0
2: 0 0 3 0
3: 3 0 0 3
où chaque paire est calculée dans l'ordre value1_formula1, value1_formula2, ... , valueN_formula(N-1), valueN_formulaN
.
Alternativement, nous pouvons évaluer nos valeurs et fonctions un à un en passant "value.var" comme une liste:
dcast(DT, formula = ID ~ Age, value.var = list("Result","Test"), fun.aggregate = list(function(x){paste0(x,collapse = "_")},length))
ID Result_function_20 Result_function_21 Result_function_22 Test_length_20 Test_length_21 Test_length_22
1: a 1_4_7 3 0 0
2: b 2_5_8 0 3 0
3: c 3_6_9 0 0 3
Nommer des colonnes dans le résultat
Par défaut, les composants de nom de colonne sont séparés par un trait de soulignement _
. Cela peut être remplacé manuellement à l'aide de l'argument sep=
:
dcast(DT, formula = Test ~ ID + Age, value.var = "Result")
Test a_20 b_21 c_22
1: OB_A 1 2 3
2: OB_B 4 5 6
3: OB_C 7 8 9
dcast(DT, formula = Test ~ ID + Age, value.var = "Result", sep = ",")
Test a,20 b,21 c,22
1: OB_A 1 2 3
2: OB_B 4 5 6
3: OB_C 7 8 9
Cela fun.aggregate
tous les fun.aggregate
ou value.var
nous utilisons:
dcast(DT, formula = Test ~ ID + Age, value.var = "Result", fun.aggregate = c(sum,length), sep = ",")
Test Result,sum,a,20 Result,sum,b,21 Result,sum,c,22 Result,length,a,20 Result,length,b,21 Result,length,c,22
1: OB_A 1 2 3 1 1 1
2: OB_B 4 5 6 1 1 1
3: OB_C 7 8 9 1 1 1
Empilement de plusieurs tables à l'aide de rbindlist
Un refrain commun en R va dans ce sens:
Vous ne devriez pas avoir un tas de tables liées avec des noms comme
DT1
,DT2
, ...,DT11
. Lire et assigner de manière itérative aux objets par leur nom est compliqué. La solution est une liste de tables de données!
Une telle liste ressemble à
set.seed(1)
DT_list = lapply(setNames(1:3, paste0("D", 1:3)), function(i)
data.table(id = 1:2, v = sample(letters, 2)))
$D1
id v
1: 1 g
2: 2 j
$D2
id v
1: 1 o
2: 2 w
$D3
id v
1: 1 f
2: 2 w
Une autre perspective est que vous devez stocker ces tables en une seule table , en les empilant. C'est simple à faire en utilisant rbindlist
:
DT = rbindlist(DT_list, id="src")
src id v
1: D1 1 g
2: D1 2 j
3: D2 1 o
4: D2 2 w
5: D3 1 f
6: D3 2 w
Ce format est beaucoup plus logique avec la syntaxe data.table, où les opérations "par groupe" sont courantes et simples.
Pour un regard plus profond, la réponse de Gregor pourrait être un bon point de départ. Jetez également un coup d' ?rbindlist
Il y a un autre exemple couvrant la lecture dans un tas de tables à partir de CSV, puis leur empilement .