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 .



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