Manipulation des données avec reshape

December 17, 2010
By

This post was kindly contributed by Alea - R - go there to comment and to read the full post.

reshape est une extension développée par Hadley Wickham. Elle permet de passer facilement d'un format de données «long» (une ligne par individu et par variable) à un format «large» (une seule ligne par individu). Elle est notamment utile pour mettre en forme les données avant utilisation des fonctions graphiques de ggplot2.

Site officiel :

Article d'introduction :

On charge l'extension après l'avoir installée :

library(reshape)

Melting

melting (fondre) consiste à transformer les données d'un format «large» à un format long. Cette opération se fait à l'aide de la fonction melt(), qui peut s'appliquer à des objets, notamment de type data.frame, matrix ou array.

Fonction melt

On part du jeu de données d'exemple :

data(smiths)
smiths

     subject time age weight height
1 John Smith    1  33     90   1.87
2 Mary Smith    1  NA     NA   1.54

On doit donner à melt une liste de variable d'identifiants et une liste de variables de mesure. Si on ne spécifie rien, melt considère les variables de type integer ou factor comme des identifiants, et les autres comme des mesures.

melt(smiths,  id=c("subject", "time"))
     subject time variable value
1 John Smith    1      age 33.00
2 Mary Smith    1      age    NA
3 John Smith    1   weight 90.00
4 Mary Smith    1   weight    NA
5 John Smith    1   height  1.87
6 Mary Smith    1   height  1.54

Est équivalent à :

melt(smiths, id=c("subject", "time"), measured=c("age", "weight", "height"))

Contrainte importante : toutes les variables de mesure doivent être du même type (factor, numeric…), sinon elles ne pourraient être regroupées dans une même colonne d'un data frame.

Valeurs manquantes

Dans le formet large, les valeurs manquantes sont indiquées explicitement par un NA. Dans le format long, elles peuvent être codées soit explicitement avec un NA, soit implicitement par la simple absence des lignes correspondantes. Le choix se fait avec l'argument na.rm de melt(), dont la valeur est FALSE par défaut :

melt(smiths, id=c("subject", "time"))
     subject time variable value
1 John Smith    1      age 33.00
2 Mary Smith    1      age    NA
3 John Smith    1   weight 90.00
4 Mary Smith    1   weight    NA
5 John Smith    1   height  1.87
6 Mary Smith    1   height  1.54
melt(smiths, id=c("subject", "time"), na.rm=TRUE)
     subject time variable value
1 John Smith    1      age 33.00
2 John Smith    1   weight 90.00
3 John Smith    1   height  1.87
4 Mary Smith    1   height  1.54

Casting

casting (mouler) permet de transformer des données préalablement "fondues" (molten) dans le format désiré à laide de la fonction cast().

Usage

cast() prend comme argument des données "fondues" et une formule.

Cette formule sépare à gauche les variables qu'on souhaite en colonnes et à droite celles qu'on souhaite en lignes.

smithsm <- melt(smiths,  id=c("subject", "time"))
smithsm

     subject time variable value
1 John Smith    1      age 33.00
2 Mary Smith    1      age    NA
3 John Smith    1   weight 90.00
4 Mary Smith    1   weight    NA
5 John Smith    1   height  1.87
6 Mary Smith    1   height  1.54
cast(smithsm, time + subject ~ variable)
  time    subject age weight height
1    1 John Smith  33     90   1.87
2    1 Mary Smith  NA     NA   1.54

Ici, les variables time et subject des données "fondues" sont conservées en colonnes dans le data frame résultat. La variable variable, par contre est transformée en lignes : chacune de ses modalités est transformée en une colonne avec comme valeur la valeur de value correspondante.

On peut utiliser le raccourci ... dans la formule poursignifier /"toutes les autres variables"/ .

cast(smithsm, ... ~ subject)
  time variable John Smith Mary Smith
1    1      age      33.00         NA
2    1   weight      90.00         NA
3    1   height       1.87       1.54
cast(smithsm, ... ~ time)
     subject variable     1
1 John Smith      age 33.00
2 John Smith   weight 90.00
3 John Smith   height  1.87
4 Mary Smith      age    NA
5 Mary Smith   weight    NA
6 Mary Smith   height  1.54

L'utilisation de cast() sans formule permet de retrouver le format "large" :

cast(smithsm)
     subject time age weight height
1 John Smith    1  33     90   1.87
2 Mary Smith    1  NA     NA   1.54

Aggrégation

On utilise le jeu de données french fries.

data(french_fries)
head(french_fries)

   time treatment subject rep potato buttery grassy rancid painty
61    1         1       3   1    2.9     0.0    0.0    0.0    5.5
25    1         1       3   2   14.0     0.0    0.0    1.1    0.0
62    1         1      10   1   11.0     6.4    0.0    0.0    0.0
26    1         1      10   2    9.9     5.9    2.9    2.2    0.0
63    1         1      15   1    1.2     0.1    0.0    1.1    5.1
27    1         1      15   2    8.8     3.0    3.6    1.5    2.3
  • time : mesure de temps en semaines
  • treatment : type d'huile utilisée
  • subject : personne ayant goûté
  • rep : replicate
  • ... : variables intensité des différents type de saveurs

On commence par fondre les données :

ffm <- melt(french_fries, id=1:4, na.rm=TRUE)
head(ffm)

  time treatment subject rep variable value
1    1         1       3   1   potato   2.9
2    1         1       3   2   potato  14.0
3    1         1      10   1   potato  11.0
4    1         1      10   2   potato   9.9
5    1         1      15   1   potato   1.2
6    1         1      15   2   potato   8.8

Pour aggréger les données, on utilise cast() en lui donnant une formule qui soit ne comporte pas toutes les colonnes présentes dans les données "fondues", soit comporte l'opérateur ., qui signifie "aucune colonne". On passe également à cast une fonction d'aggrégation (fun.aggregate), qui est =length par défaut.

Pour obtenir l'aggrégation d'une variable, on utilise . en ligne ou en colonne. Pa rxemple, le nombre global de mesures effectuées pour chaque type d'huile s'obtient avec :

cast(ffm, treatment ~ ., length)
  treatment (all)
1         1  1159
2         2  1157
3         3  1155
cast(ffm, . ~ treatment, length)
  value    1    2    3
1 (all) 1159 1157 1155

Le nombre de mesures effectuées par sujet et par type d'huile peut s'obtenir de différentes manières :

cast(ffm, treatment ~ subject, length)
  treatment  3  10  15  16  19 31  51  52  63  78 79 86
1         1 90 100 100 100 100 90 100 100 100 100 89 90
2         2 90 100 100  99 100 90 100 100 100 100 88 90
3         3 90 100  95 100 100 90 100 100 100 100 90 90
cast(ffm, subject ~ treatment, length)
   subject   1   2   3
1        3  90  90  90
2       10 100 100 100
3       15 100 100  95
4       16 100  99 100
5       19 100 100 100
6       31  90  90  90
7       51 100 100 100
8       52 100 100 100
9       63 100 100 100
10      78 100 100 100
11      79  89  88  90
12      86  90  90  90
cast(ffm, subject + treatment ~ ., length)
   subject treatment (all)
1        3         1    90
2        3         2    90
3        3         3    90
4       10         1   100
5       10         2   100
6       10         3   100
7       15         1   100
8       15         2   100
9       15         3    95
10      16         1   100
11      16         2    99
12      16         3   100
13      19         1   100
14      19         2   100
15      19         3   100
16      31         1    90
17      31         2    90
18      31         3    90
19      51         1   100
20      51         2   100
21      51         3   100
22      52         1   100
23      52         2   100
24      52         3   100
25      63         1   100
26      63         2   100
27      63         3   100
28      78         1   100
29      78         2   100
30      78         3   100
31      79         1    89
32      79         2    88
33      79         3    90
34      86         1    90
35      86         2    90
36      86         3    90
cast(ffm, . ~ subject + treatment, length)
  value 3_1 3_2 3_3 10_1 10_2 10_3 15_1 15_2 15_3 16_1 16_2 16_3 19_1 19_2
1 (all)  90  90  90  100  100  100  100  100   95  100   99  100  100  100
  19_3 31_1 31_2 31_3 51_1 51_2 51_3 52_1 52_2 52_3 63_1 63_2 63_3 78_1
1  100   90   90   90  100  100  100  100  100  100  100  100  100  100
  78_2 78_3 79_1 79_2 79_3 86_1 86_2 86_3
1  100  100   89   88   90   90   90   90

On voit que si plusieurs variables sont spécifiées en colonnes, leurs noms sont concaténés pour former les colonnes du résultat.

On peut utiliser d'autres fonctions d'aggrégation, par exemple pour calculer les notes moyennes obtenues pour chaque traitement :

cast(ffm, treatment  ~ variable, mean)
  treatment   potato  buttery    grassy   rancid   painty
1         1 6.887931 1.780087 0.6491379 4.065517 2.583621
2         2 7.001724 1.973913 0.6629310 3.624569 2.455844
3         3 6.967965 1.717749 0.6805195 3.866667 2.525541

On peut également produire des listes à l'aide de l'opérateur |. L'exemple suivant donne les valeurs moyennes pour chaque traitement par individu :

cast(ffm, treatment ~ variable | subject, mean)
$`3`
  treatment   potato   buttery     grassy   rancid   painty
1         1 6.216667 0.3722222 0.18888889 2.105556 3.111111
2         2 6.738889 0.5888889 0.10555556 3.138889 2.477778
3         3 5.294444 0.7666667 0.09444444 2.855556 2.866667

$`10`
  treatment potato buttery grassy rancid painty
1         1  9.955    6.75  0.585   4.02  1.375
2         2  9.995    6.98  0.475   2.15  0.820
3         3 10.030    6.45  0.145   3.11  0.690

$`15`
  treatment   potato   buttery    grassy   rancid   painty
1         1 3.360000 0.7200000 0.4200000 3.965000 3.260000
2         2 4.405000 1.3150000 0.3400000 2.285000 2.060000
3         3 3.963158 0.9894737 0.4421053 2.547368 2.368421

$`16`
  treatment potato  buttery grassy rancid painty
1         1  6.495 3.260000  0.755   4.12  1.230
2         2  6.450 3.373684  1.055   3.40  0.455
3         3  6.860 2.700000  1.125   3.20  0.555

$`19`
  treatment potato buttery grassy rancid painty
1         1  9.385   3.055  2.020  5.360  2.775
2         2  8.640   2.450  1.135  5.405  4.155
3         3  8.740   1.725  2.070  7.240  3.905

$`31`
  treatment   potato   buttery     grassy   rancid   painty
1         1 8.844444 0.4444444 0.08888889 5.944444 3.211111
2         2 8.033333 0.6166667 0.15555556 6.050000 5.061111
3         3 9.027778 0.6500000 0.17222222 6.577778 5.127778

$`51`
  treatment potato buttery grassy rancid painty
1         1 10.675   2.640   1.05  5.150  1.955
2         2  9.985   3.795   1.57  4.670  2.255
3         3 10.220   3.130   1.35  4.915  2.545

$`52`
  treatment potato buttery grassy rancid painty
1         1  5.060   0.805  0.875  4.285  2.645
2         2  5.515   1.025  1.180  4.225  2.195
3         3  5.475   0.865  0.765  3.160  2.660

$`63`
  treatment potato buttery grassy rancid painty
1         1  6.775   0.025  0.000  6.055  3.855
2         2  8.415   0.105  0.010  5.090  4.355
3         3  8.060   0.065  0.125  6.185  3.100

$`78`
  treatment potato buttery grassy rancid painty
1         1   3.62   0.735  0.540  1.505  3.490
2         2   3.78   0.295  0.755  1.550  2.725
3         3   4.00   0.705  0.665  1.185  3.520

$`79`
  treatment   potato   buttery    grassy    rancid     painty
1         1 8.061111 0.2823529 0.3444444 0.5666667 0.00000000
2         2 7.938889 0.6941176 0.2555556 1.0333333 0.00000000
3         3 7.733333 0.5722222 0.1166667 1.1777778 0.02777778

$`86`
  treatment   potato  buttery    grassy   rancid   painty
1         1 4.183333 1.772222 0.8055556 5.494444 4.105556
2         2 3.994444 2.061111 0.7833333 4.522222 2.844444
3         3 3.866667 1.633333 0.9444444 4.105556 3.027778

Marges

On peut ajouter des marges aux résultats obtenus.

cast(ffm, treatment ~ rep, sum, margins=TRUE)
  treatment      1      2   (all)
1         1 1857.3 1845.1  3702.4
2         2 1836.5 1803.9  3640.4
3         3 1739.1 1901.1  3640.2
4     (all) 5432.9 5550.1 10983.0
cast(ffm, treatment + rep ~ time, sum, margins=TRUE)
   treatment   rep      1      2      3      4      5      6      7      8
1          1     1  156.4  212.8  206.0  181.2  207.5  181.5  156.4  185.1
2          1     2  216.4  195.1  193.6  153.7  204.5  184.8  157.7  216.4
3          1 (all)  372.8  407.9  399.6  334.9  412.0  366.3  314.1  401.5
4          2     1  186.6  212.7  171.8  192.7  157.3  183.4  175.0  173.4
5          2     2  168.3  157.3  185.8  187.1  172.8  214.6  172.0  188.6
6          2 (all)  354.9  370.0  357.6  379.8  330.1  398.0  347.0  362.0
7          3     1  189.2  211.9  172.3  190.2  150.6  160.9  165.2  150.4
8          3     2  216.7  180.5  199.2  191.8  183.0  191.8  218.3  174.6
9          3 (all)  405.9  392.4  371.5  382.0  333.6  352.7  383.5  325.0
10     (all) (all) 1133.6 1170.3 1128.7 1096.7 1075.7 1117.0 1044.6 1088.5
       9     10   (all)
1  176.2  194.2  1857.3
2  121.6  201.3  1845.1
3  297.8  395.5  3702.4
4  184.8  198.8  1836.5
5  145.2  212.2  1803.9
6  330.0  411.0  3640.4
7  173.3  175.1  1739.1
8  163.7  181.5  1901.1
9  337.0  356.6  3640.2
10 964.8 1163.1 10983.0

Valeurs multiples

On peut agréger avec des fonctions renvoyant plusieurs valeurs :

cast(ffm, treatment  ~ . , summary)
  treatment Min. X1st.Qu. Median  Mean X3rd.Qu. Max.
1         1    0        0    1.6 3.194      5.4 14.9
2         2    0        0    1.4 3.146      5.4 14.9
3         3    0        0    1.5 3.152      5.7 14.5

Ou passer en argument un vecteur de fonctions :

cast(ffm, treatment  ~ rep , c(min, max))
  treatment 1_min 1_max 2_min 2_max
1         1     0  14.9     0  14.3
2         2     0  14.9     0  13.7
3         3     0  14.5     0  14.0

Exemple d'utilisation

Soit les données fictives suivantes :

  text <- 
  "REGION VILLE   ANNEE   POP     CHOM
  Rhone-Alpes     Lyon    1990    120000  8000
  Rhone-Alpes     Lyon    1999    127000  11000
  Rhone-Alpes   Grenoble        1990    68000   4000
  Rhone-Alpes   Grenoble        1999    77000   7000
  Auvergne      Clermont        1990    85000   3500
  Auvergne      Clermont        1999    88000   3800"
text.conn <- textConnection(text, encoding="UTF-8")
d <- read.table(text.conn, header=TRUE)
close(text.conn)
str(d)
'data.frame':	6 obs. of  5 variables:
 $ REGION: Factor w/ 2 levels "Auvergne","Rhone-Alpes": 2 2 2 2 1 1
 $ VILLE : Factor w/ 3 levels "Clermont","Grenoble",..: 3 3 2 2 1 1
 $ ANNEE : int  1990 1999 1990 1999 1990 1999
 $ POP   : int  120000 127000 68000 77000 85000 88000
 $ CHOM  : int  8000 11000 4000 7000 3500 3800

On commence par les "fondre" :

dm <- melt(d, id=1:3)
dm
        REGION    VILLE ANNEE variable  value
1  Rhone-Alpes     Lyon  1990      POP 120000
2  Rhone-Alpes     Lyon  1999      POP 127000
3  Rhone-Alpes Grenoble  1990      POP  68000
4  Rhone-Alpes Grenoble  1999      POP  77000
5     Auvergne Clermont  1990      POP  85000
6     Auvergne Clermont  1999      POP  88000
7  Rhone-Alpes     Lyon  1990     CHOM   8000
8  Rhone-Alpes     Lyon  1999     CHOM  11000
9  Rhone-Alpes Grenoble  1990     CHOM   4000
10 Rhone-Alpes Grenoble  1999     CHOM   7000
11    Auvergne Clermont  1990     CHOM   3500
12    Auvergne Clermont  1999     CHOM   3800

Populations totales par région :

cast(dm, REGION ~ variable, sum)
       REGION    POP  CHOM
1    Auvergne 173000  7300
2 Rhone-Alpes 392000 30000

Caractéristiques des variables par région :

cast(dm, REGION ~ . | variable, summary)
$POP
       REGION  Min. X1st.Qu. Median  Mean X3rd.Qu.   Max.
1    Auvergne 85000    85750  86500 86500    87250  88000
2 Rhone-Alpes 68000    74750  98500 98000   121800 127000

$CHOM
       REGION Min. X1st.Qu. Median Mean X3rd.Qu.  Max.
1    Auvergne 3500     3575   3650 3650     3725  3800
2 Rhone-Alpes 4000     6250   7500 7500     8750 11000

Tranformation en format "large" :

cast(dm, REGION + VILLE ~ variable + ANNEE)
       REGION    VILLE POP_1990 POP_1999 CHOM_1990 CHOM_1999
1    Auvergne Clermont    85000    88000      3500      3800
2 Rhone-Alpes Grenoble    68000    77000      4000      7000
3 Rhone-Alpes     Lyon   120000   127000      8000     11000

Représentation graphique (avec ggplot2) de deux variables simultanméent :

library(ggplot2)
dmg <- melt(d, id=c("ANNEE"), measure=c("POP", "CHOM"))
dmg
   ANNEE variable  value
1   1990      POP 120000
2   1999      POP 127000
3   1990      POP  68000
4   1999      POP  77000
5   1990      POP  85000
6   1999      POP  88000
7   1990     CHOM   8000
8   1999     CHOM  11000
9   1990     CHOM   4000
10  1999     CHOM   7000
11  1990     CHOM   3500
12  1999     CHOM   3800
vars <- cast(dmg, variable + ANNEE ~ ., sum)
vars

  variable ANNEE  (all)
1      POP  1990 273000
2      POP  1999 292000
3     CHOM  1990  15500
4     CHOM  1999  21800
qplot(ANNEE, vars$"(all)", data=vars, color=variable, geom="line")

http://alea.fr.eu.org/public/_____________reshape1.png

Tags:

Comments are closed.