Matrix

Rien à voir avec le film des Wachowski…

La dernière fois, nous avons vu cinq types de vecteurs : numeric, integer, character, Date et logical. L’heure est venue de vous présenter les matrices (la classe matrix).

Le plus simple est encore d’en construire une. Soit un vecteur numérique :

rm(list = ls())
x <- 1:36

On constate bien que :

> class(x)
[1] "integer"

On lui assigne des dimensions avec :

dim(x) <- c(12, 3)

Et on obtient :

> x
      [,1] [,2] [,3]
 [1,]    1   13   25
 [2,]    2   14   26
 [3,]    3   15   27
 [4,]    4   16   28
 [5,]    5   17   29
 [6,]    6   18   30
 [7,]    7   19   31
 [8,]    8   20   32
 [9,]    9   21   33
[10,]   10   22   34
[11,]   11   23   35
[12,]   12   24   36
> class(x)
[1] "matrix"

C’est une manière de voir ce qu’est une matrice ; c’est un vecteur numérique auquel on a donné deux dimensions pour en faire un tableau de données : un nombre de lignes (ici 12) et un nombre de colonnes (3).

Une autre manière plus conventionnelle d’obtenir le même résultat consiste à passer par la fonction matrix :

M <- matrix(x, 12, 3)

Par convention, on donne toujours le nombre de lignes (nrow) puis le nombre colonnes (ncol).

Avec notre matrice M vous pouvez vérifier :

> M <- matrix(x, 12, 3)
> nrow(M)
[1] 12
> ncol(M)
[1] 3
> dim(M)
[1] 12  3

Vous pouvez aussi créer des matrices avec des characters :

> matrix(letters[1:15], 5, 3)
     [,1] [,2] [,3]
[1,] "a"  "f"  "k" 
[2,] "b"  "g"  "l" 
[3,] "c"  "h"  "m" 
[4,] "d"  "i"  "n" 
[5,] "e"  "j"  "o"

C’est possible mais en principe les matrices sont plutôt prévues pour des données numériques.

Observons bien ce qu’affiche la console :

> head(M, 3)
     [,1] [,2] [,3]
[1,]    1   13   25
[2,]    2   14   26
[3,]    3   15   27

(Vous observez au passage que head et tail fonctionnent : elles sélectionnent les n premières ou dernières lignes d’une matrice.)

Chaque ligne est identifiée par un [i, ]i est le numéro de la ligne et chaque colonne est identifiée par un [, j] ou j est le numéro de la colonne.

Devinez donc comment je vais faire pour récupérer les lignes 1, 3 et 5 de M ?

Facile :

> M[c(1, 3, 5), ]
     [,1] [,2] [,3]
[1,]    1   13   25
[2,]    3   15   27
[3,]    5   17   29

Si je souhaite récupérer la première et la troisième colonne :

M[, c(1, 3)]

Et si je veux les lignes 1, 3 et 5 mais seulement pour les deux premières colonnes :

M[c(1, 3, 5), 1:2]

Ou : M[c(1, 3, 5), -3]

Bref, le système d’indexation que nous avons vu pour les vecteurs fonctionne aussi pour les matrices à ceci près que, comme les matrices sont des objets en deux dimensions, la syntaxe n’est pas x[i] mais x[i, j].

Vous pouvez faire ceci :

> M[1:3, rep(1, 5)]
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    1    1    1
[2,]    2    2    2    2    2
[3,]    3    3    3    3    3

Ou encore cela :

> M[M[, 1] < 5, ]
     [,1] [,2] [,3]
[1,]    1   13   25
[2,]    2   14   26
[3,]    3   15   27
[4,]    4   16   28

(Notez que M[indice, ] renvoie toutes les colonnes de M de la même manière que M[, indice] renvoie toutes les lignes.)

Un petit détail pratique. Lorsque que vous ne sélectionnez qu’une seule colonne ou qu’une seule ligne d’une matrice, R casse les dimensions de la matrice (i.e. il vous renvoie un vecteur).

> M[, ncol(M)]
 [1] 25 26 27 28 29 30 31 32 33 34 35 36
> M[1, ]
[1]  1 13 25

Si vous souhaitez éviter ça (i.e. vous voulez récupérer une matrice de dimensions [1, 3] par exemple), utilisez l’argument drop = FALSE :

> M[1, , drop = FALSE]
     [,1] [,2] [,3]
[1,]    1   13   25

Évidemment, on peut aussi utiliser ce système pour remplacer les éléments d’une matrice. Pour remplir la première ligne de 1 :

> M[1, ] <- 1
> M
      [,1] [,2] [,3]
 [1,]    1    1    1
 [2,]    2   14   26
 [3,]    3   15   27
 (…)

Pour vider la matrice :

> M[] <- NA
> M
      [,1] [,2] [,3]
 [1,]   NA   NA   NA
 [2,]   NA   NA   NA
 [3,]   NA   NA   NA
 (…)

Pour la re-remplir :

> M[] <- 1:36
> M
      [,1] [,2] [,3]
 [1,]    1   13   25
 [2,]    2   14   26
 [3,]    3   15   27
 (…)

Mais il y a encore mieux. Créez une matrice vide :

> X <- matrix(NA, 3, 3)
> X
     [,1] [,2] [,3]
[1,]   NA   NA   NA
[2,]   NA   NA   NA
[3,]   NA   NA   NA

Avec diag, remplissez la diagonale de 1 :

diag(X) <- 1

Et puisque :

> is.na(X)
      [,1]  [,2]  [,3]
[1,] FALSE  TRUE  TRUE
[2,]  TRUE FALSE  TRUE
[3,]  TRUE  TRUE FALSE

Nous pouvons écrire :

> X[is.na(X)] <- 0
> X
     [,1] [,2] [,3]
[1,]    1    0    0
[2,]    0    1    0
[3,]    0    0    1

Oh ! La matrice identité !

Notez que vous pouviez aller plus vite avec :

X <- matrix(0, 3, 3)
diag(X) <- 1

C’est-à-dire que vous pouvez indexer une matrice avec une matrice de mode logical (et de mêmes dimensions) :

> R <- matrix(rivers[1:15], 5, 3)
> R <= 350
      [,1]  [,2]  [,3]
[1,] FALSE FALSE  TRUE
[2,]  TRUE FALSE  TRUE
[3,]  TRUE  TRUE  TRUE
[4,] FALSE FALSE  TRUE
[5,] FALSE FALSE FALSE
> R[R <= 350] <- 0
> R
     [,1] [,2] [,3]
[1,]  735  450    0
[2,]    0 1459    0
[3,]    0    0    0
[4,]  392  465    0
[5,]  524  600  870

Vous pouvez donner des noms aux lignes et aux colonnes d’une matrice :

rownames(M) <- month.abb
colnames(M) <- 2001:2003

Ou :

dimnames(M) <- list(month.abb, 2001:2003)

(Teaser : on verra les objets de classe list une autre fois...)

Ce qui nous donne :

> M
    2001 2002 2003
Jan    1   13   25
Feb    2   14   26
Mar    3   15   27
(…)

… et nous permet de faire :

> diff(M[c("Mar", "Jun", "Sep", "Dec"), ])
    2001 2002 2003
Jun    3    3    3
Sep    3    3    3
Dec    3    3    3

Sur les matrices, diff travaille par colonne.

Si c’est par lignes que vous souhaitiez calculer des différences, il suffit de transposer la matrice avec t :

> t(M)
     Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2001   1   2   3   4   5   6   7   8   9  10  11  12
2002  13  14  15  16  17  18  19  20  21  22  23  24
2003  25  26  27  28  29  30  31  32  33  34  35  36

D’appliquer diff et de re-transposer :

> t(diff(t(M)))
    2002 2003
Jan   12   12
Feb   12   12
Mar   12   12
(…)

Fascinant n’est-ce-pas ?

Découpons M en deux matrices :

M1 <- M[1:6, ]
M2 <- M[7:12, ]

Ce qui fait que :

> dim(M1) == dim(M2)
[1] TRUE TRUE

Comme pour les vecteurs, vous pouvez utiliser les opérateurs arithmétiques et le recyclage fonctionne :

> (matrix(1, 5, 3) + matrix(2, 5, 3))^2
     [,1] [,2] [,3]
[1,]    9    9    9
[2,]    9    9    9
[3,]    9    9    9
[4,]    9    9    9
[5,]    9    9    9

Observez comment fonctionne le produit d’une matrice est d’un vecteur :

> matrix(1, 5, 3) * 1:3
     [,1] [,2] [,3]
[1,]    1    3    2
[2,]    2    1    3
[3,]    3    2    1
[4,]    1    3    2
[5,]    2    1    3

Peut-être souhaitiez-vous faire ça :

> t(t(matrix(1, 5, 3)) * 1:3)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    1    2    3
[3,]    1    2    3
[4,]    1    2    3
[5,]    1    2    3

Cela dit, si c’est vraiment ça que vous vouliez faire…

matrix(1:3, 5, 3, byrow = TRUE)

… eut été plus simple.

Deux fonctions très utiles dès lors qu’on travaille avec des matrices sont rbind (lier par row)…

> rbind(M1, M2)
    2001 2002 2003
Jan    1   13   25
Feb    2   14   26
Mar    3   15   27
(…)
Dec   12   24   36

… et cbind (pour lier par column) :

> cbind(M1, M2)
    2001 2002 2003 2001 2002 2003
Jan    1   13   25    7   19   31
Feb    2   14   26    8   20   32
Mar    3   15   27    9   21   33
Apr    4   16   28   10   22   34
May    5   17   29   11   23   35
Jun    6   18   30   12   24   36

Enfin, pour les amateurs de produits matriciels :

> M1 %*% t(M2)
     Jul  Aug  Sep  Oct  Nov  Dec
Jan 1029 1068 1107 1146 1185 1224
Feb 1086 1128 1170 1212 1254 1296
Mar 1143 1188 1233 1278 1323 1368
Apr 1200 1248 1296 1344 1392 1440
May 1257 1308 1359 1410 1461 1512
Jun 1314 1368 1422 1476 1530 1584

La fonction d’aide de cet opérateur est là :

> help("%*%")

À ce stade, vous devriez commencer à être au point sur les matrices ; je vais donc vous faire un peu peur :

Tout à l’heure, nous avons créé notre première matrice en faisant :

x <- 1:36
dim(x) <- c(12, 3)

Essayez ça :

x <- 1:36
dim(x) <- c(4, 3, 3)

Exécutez :

> x
, , 1

     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12

, , 2

     [,1] [,2] [,3]
[1,]   13   17   21
[2,]   14   18   22
[3,]   15   19   23
[4,]   16   20   24

, , 3

     [,1] [,2] [,3]
[1,]   25   29   33
[2,]   26   30   34
[3,]   27   31   35
[4,]   28   32   36
> class(x)
[1] "array"

Oui, vous avez bien compris : cet animal-là est un objet à trois dimensions ; un cube de données.

Essayez ça :

x[2,,]
x[,2,]
x[,,2]

Vous pouvez même recommencer avec…

x <- 1:36
dim(x) <- c(3, 2, 2, 3)

… et vous obtiendrez un autre array mais à quatre dimensions cette fois.

Aucun commentaire:

Enregistrer un commentaire