.. include:: weblinks.txt .. _arrays: Tableaux multidimensionnels =========================== En R, les tableaux multi dimensionnels sont appelés ``array``. Il existe 2 cas particuliers d'un ``array`` : - le vecteur qui est un ``array`` de dimension 1 ; - la matrice (``matrix``) qui est un ``array`` de dimension 2. Un vecteur de dimensions est un vecteur d'entiers strictement positifs. Si la longueur de ce vecteur est ``k``, on a un ``array`` de dimension ``k``. Chacune des dimensions est indexée de ``1`` jusqu'à la valeur donnée par le vecteur dimension. Tableau ------- Les valeurs contenues dans un vecteur peuvent être structurées en ``array`` en utilisant l'attribut ``dim``. Construisons un vecteur ``z`` de 1500 elements:: > z <- sample(seq(1,100), size=1500, replace=T) > str(z) int [1:1500] 75 63 34 73 65 9 79 60 37 45 ... > z[1:18] [1] 75 63 34 73 65 9 79 60 37 45 10 52 16 35 63 72 89 40 A la création, l'attribut ``dim`` n'existe pas:: > attributes(z) NULL On peut lui affecter un vecteur dimension:: > dim(z) <- c(3,5,100) ce qui permet de considérer ``z`` comme un ``array`` 3 x 5 x 100:: > str(z) int [1:3, 1:5, 1:100] 75 63 34 73 65 9 79 60 37 45 ... > attributes(z) $dim [1] 3 5 100 > z[1:3,1:5,1] [,1] [,2] [,3] [,4] [,5] [1,] 75 73 79 45 16 [2,] 63 65 60 10 35 [3,] 34 9 37 52 63 .. tip:: Pour les ``array`` de dimension 1 et 2, les fonctions :func:`array` et :func:`matrix` permettent une construction plus naturelle. .. admonition:: Question Observer comment les valeurs sont distribuées dans la structure multi dimensionnelle. Quel est l'indice qui varie le plus vite ? Le plus lentement ? .. Le premier indice est celui qui varie le plus vite, le dernier indice celui qui varie le plus lentement. Si on considère un ``array`` ``a`` dont le vecteur dimension est ``c(3,4,2)``, alors il y a 3 x 4 x 2 = 24 valeurs dans ``a``. Ces valeurs sont stockées dans l'ordre suivant : - ``a[1,1,1]`` - ``a[2,1,1]`` - ... - ``a[2,4,2]`` - ``a[3,4,2]`` Illustrons ceci:: > a <- sample(seq(1,100), size=24) > str(a) int [1:24] 58 27 79 75 81 71 11 45 8 43 ... > dim(a) <- c(3,4,2) > a[1,1,1] [1] 58 > a[2,1,1] [1] 27 > a[3,1,1] [1] 79 > a[1,2,1] [1] 75 Indexation et sous tableaux --------------------------- Chaque élément d'un ``array`` est accessible individuellement avec une syntaxe du type:: > a[1,1,1] [1] 58 On peut extraire des sous sections d'un ``array`` plutôt que des éléments individuels, en passant des vecteurs à l'opérateur d'indexation plutôt que des scalaires. Si le champ est vide, la totalité des indices est utilisée sur la dimension correspondante. Par exemple, ``a[2,,]`` est un ``array`` 4 x 2, ce qui revient à dire que son vecteur dimension est ``c(4,2)``. Ce serait équivalent de construire la sous section de la façon suivante:: > c(a[2,1,1], a[2,2,1], a[2,3,1], a[2,4,1], a[2,1,2], a[2,2,2], a[2,3,2], a[2,4,2]) .. important:: La syntaxe ``a[2,,]`` signifie qu'on fixe le premier indice à ``2`` et que l'on prend toutes les valeurs du deuxième, et toutes les valeurs du troisième. Si on s'intéresse aux valeurs que contient cette sélection (slicing):: > a[2,,] [,1] [,2] [1,] 27 15 [2,] 81 40 [3,] 45 31 [4,] 12 25 > a , , 1 [,1] [,2] [,3] [,4] [1,] 58 75 11 43 [2,] 27 81 45 12 [3,] 79 71 8 86 , , 2 [,1] [,2] [,3] [,4] [1,] 20 67 90 80 [2,] 15 40 31 25 [3,] 85 61 36 72 > a[,,] , , 1 [,1] [,2] [,3] [,4] [1,] 58 75 11 43 [2,] 27 81 45 12 [3,] 79 71 8 86 , , 2 [,1] [,2] [,3] [,4] [1,] 20 67 90 80 [2,] 15 40 31 25 [3,] 85 61 36 72 Le vecteur dimension retourné par la fonction :func:`dim` peut être utilisé des deux cotés de l'opérateur d'assignation:: > dim(a) <- c(3,4,2) # on the left side > d <- dim(a[2,,]) # on the right side > d [1] 4 2 L'utilisation d'index négatifs pour exclure (plutôt que sélectionner) est possible également pour les ``array``. Ici, on écarte la première colonne et la première ligne de ``a[,,2]``:: > a[-1,-1,2] [,1] [,2] [,3] [1,] 40 31 25 [2,] 61 36 72 Si un seul indice (ou un vecteur d'indices) est utilisé pour l'indexation d'un ``array``, on considère ce dernier comme un simple vecteur (sans multi dimension) et l'élément correspondant est retourné:: > a[1] [1] 58 > a[c(1,2,3,4)] [1] 58 27 79 75 Indexation par matrice ---------------------- Pour l'indexation d'un ``array``, on vient de voir qu'on peut utiliser un vecteur d'index. On peut également passer une matrice à l'opérateur d'indexation. La matrice définit une séquence d'index. Elle doit contenir autant de colonnes que la dimension de l'``array`` et autant de lignes que le nombre d'élément que l'on veut extraire. Prenons un exemple avec un ``array`` de dimension 4 x 5:: > x <- array(1:20, dim=c(4,5)) # Generate a 4 by 5 array. > x [,1] [,2] [,3] [,4] [,5] [1,] 1 5 9 13 17 [2,] 2 6 10 14 18 [3,] 3 7 11 15 19 [4,] 4 8 12 16 20 Si on veut extraire les éléments ``x[1,3]``, ``x[2,2]`` et ``x[3,1]``, on crée la matrice d'indexation associée:: > i <- array(c(1:3,3:1), dim=c(3,2)) > i # i is a 3 by 2 index array. [,1] [,2] [1,] 1 3 [2,] 2 2 [3,] 3 1 Chaque ligne de la matrice correspond bien aux indices que l'on veut extraire. L'extraction est ensuite directe:: > x[i] # Extract x[1,3], x[2,2] and x[3,1] [1] 9 6 3 On peut bien sûr utiliser l'opérateur d'indexation pour une affectation:: > x[i] <- 0 # Replace those elements by zeros. > x [,1] [,2] [,3] [,4] [,5] [1,] 1 5 0 13 17 [2,] 2 0 10 14 18 [3,] 0 7 11 15 19 [4,] 4 8 12 16 20 > .. warning:: Les indices négatifs ne sont pas permis dans les matrices d'indexation, mais les valeurs ``NA`` et ``0`` le sont. Les lignes de la matrice d'indexation contenant un ``0`` sont ignorées. Les lignes de la matrice d'indexation contenant un ``NA`` produisent des ``NA``. .. warning:: Une matrice d'indexation doit être numérique. Si elle ne l'est pas, elle est traitée comme un vecteur d'indexation. La fonction :func:`array` ------------------------- Jusqu'à présent, les ``array`` ont été construits par utilisation d'un attribut ``dim`` associé à un vecteur. On peut également utiliser la fonction :func:`array` (voir `la documentation `__). On l'utilise de la façon suivante:: > z <- array(data_vector, dim_vector) Par exemple, si le vecteur ``h`` contient 24 éléments (ou moins) on peut construire un ``array`` ``z`` de la façon suivante:: > z <- array(h, dim=c(3,4,2)) Si ``h`` est exactement de dimension 24, le résultat est identique à l'instruction:: > z <- h ; dim(z) <- c(3,4,2) Démonstration:: > h <- seq(1,24) > z <- array(h, dim=c(3,4,2)) > z , , 1 [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 2 5 8 11 [3,] 3 6 9 12 , , 2 [,1] [,2] [,3] [,4] [1,] 13 16 19 22 [2,] 14 17 20 23 [3,] 15 18 21 24 Sans surprise, si ``h`` a moins de 24 éléments, la règle de recyclage est utilisée:: > h <- seq(1,16) > z <- array(h, dim=c(3,4,2)) > z , , 1 [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 2 5 8 11 [3,] 3 6 9 12 , , 2 [,1] [,2] [,3] [,4] [1,] 13 16 3 6 [2,] 14 1 4 7 [3,] 15 2 5 8 .. warning:: Essayer de forcer la dimension de ``h`` produit une erreur. .. code-block:: r > dim(h) <- c(3,4,2) Error in dim(h) <- c(3, 4, 2) dims [product 24] do not match the length of object [16] Une utilisation "extrême" de la règle de recyclage permet de construire un ``array`` rempli de ``0``:: > z <- array(0, c(3,4,2)) Cette construction initialise le vecteur dimension:: > dim(z) [1] 3 4 2 et l'instruction ``z[1:24]`` construit un vecteur des valeurs de ``z``:: > z[1:24] [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 2 3 4 5 6 7 8 Un ``array`` peut être utilisé avec les opérateurs arithmétiques et le résultat est un ``array`` construit élément par élément:: > x <- array(1:20, dim=c(4,5)) > x [,1] [,2] [,3] [,4] [,5] [1,] 1 5 9 13 17 [2,] 2 6 10 14 18 [3,] 3 7 11 15 19 [4,] 4 8 12 16 20 > 2*x+1 [,1] [,2] [,3] [,4] [,5] [1,] 3 11 19 27 35 [2,] 5 13 21 29 37 [3,] 7 15 23 31 39 [4,] 9 17 25 33 41 .. important:: On peut convertir un ``array`` ou une ``matrix`` en vecteur avec la fonction de coercition :func:`as.vector`. .. code-block:: r > X<-matrix(1:4, nrow=2) > vec <- as.vector(X) > vec [1] 1 2 3 4 Calcul matriciel ---------------- Comme précisé plus haut, une matrice est un cas particulier d'un ``array`` qui dans ce cas est de dimension 2. Il existe cependant plusieurs fonctions spécifiques aux matrices, ce qui justifie de traiter ce cas particulier. La fonction de transposition :func:`t` est un exemple:: > x [,1] [,2] [,3] [,4] [,5] [1,] 1 5 9 13 17 [2,] 2 6 10 14 18 [3,] 3 7 11 15 19 [4,] 4 8 12 16 20 > t(x) [,1] [,2] [,3] [,4] [1,] 1 2 3 4 [2,] 5 6 7 8 [3,] 9 10 11 12 [4,] 13 14 15 16 [5,] 17 18 19 20 Les fonctions :func:`nrow` (nombre de lignes) et :func:`ncol` (nombre de colonnes) également:: > nrow(x) [1] 4 > ncol(x) [1] 5 Multiplication matricielle .......................... Le simple opérateur de multiplication ``*`` effectue des opérations élément par élément lorsqu'il est utilisé avec des matrices. On peut effectue une vraie multiplication matricielle, au sens mathématique du terme, avec l'opérateur ``%*%``:: > x <- matrix(1:4, nrow=2) > x [,1] [,2] [1,] 1 3 [2,] 2 4 > y <- matrix(5:8, nrow=2) > y [,1] [,2] [1,] 5 7 [2,] 6 8 > x*y [,1] [,2] [1,] 5 21 [2,] 12 32 > x %*% y [,1] [,2] [1,] 23 31 [2,] 34 46 Si l'opération n'est pas valide, un message d'erreur est affiché: .. code-block:: r > x <- matrix(1:6, nrow=2) > x [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 > y <- matrix(7:12, nrow=3) > y [,1] [,2] [1,] 7 10 [2,] 8 11 [3,] 9 12 > x*y Error in x * y : non-conformable arrays > x %*% y [,1] [,2] [1,] 76 103 [2,] 100 136 .. tip:: Extraire un vecteur colonne n'est pas toujours direct car R essaye systématiquement de structurer le résultat avec la plus petite dimension, c'est à dire un vecteur ligne. .. code-block:: r > x[,3] [1] 5 6 On peut passer le paramètre ``drop`` pour obtenir le résultat souhaité. .. code-block:: r > x[,3, drop=FALSE] [,1] [1,] 5 [2,] 6 La multiplication matricielle fonctionne évidemment si un des opérandes est un vecteur, pour peu que les règles de dimension soient satisfaites:: > v <- 7:9 > x %*% v [,1] [1,] 76 [2,] 100 Construction de matrices par ligne et par colonne ................................................. Les matrices peuvent être construites par concaténation avec les fonctions R core :func:`rbind` et :func:`cbind`: - :func:`rbind` construit la matrice par concaténation verticale, en "ajoutant" des lignes - :func:`cbind` construit la matrice par concaténation horizontale, en "ajoutant" des colonnes Un exemple:: > x <- rbind(seq(1,5,2), seq(2,6,2)) > x [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 > x <- cbind(1:2, 3:4, 5:6) > x [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 .. warning:: La règle de recyclage s'applique également avec les fonctions :func:`rbind` et :func:`cbind` mais ce n'est pas une bonne pratique de la laisser se mettre en oeuvre. Les fonctions :func:`rbind` et :func:`cbind` peuvent prendre des matrices en argument: .. code-block:: r > A<-matrix(c(1:15),nrow=5) > A [,1] [,2] [,3] [1,] 1 6 11 [2,] 2 7 12 [3,] 3 8 13 [4,] 4 9 14 [5,] 5 10 15 > B<-matrix(c(16:30),nrow=5) > B [,1] [,2] [,3] [1,] 16 21 26 [2,] 17 22 27 [3,] 18 23 28 [4,] 19 24 29 [5,] 20 25 30 > X<-cbind(A,B) > X [,1] [,2] [,3] [,4] [,5] [,6] [1,] 1 6 11 16 21 26 [2,] 2 7 12 17 22 27 [3,] 3 8 13 18 23 28 [4,] 4 9 14 19 24 29 [5,] 5 10 15 20 25 30 > Y<-rbind(A,B) > Y [,1] [,2] [,3] [1,] 1 6 11 [2,] 2 7 12 [3,] 3 8 13 [4,] 4 9 14 [5,] 5 10 15 [6,] 16 21 26 [7,] 17 22 27 [8,] 18 23 28 [9,] 19 24 29 [10,] 20 25 30 .. important:: Le résultat produit par :func:`rbind` ou :func:`cbind` est une ``matrix``. Par conséquent on peut utiliser ces fonctions pour produire un vecteur ligne ou colonne. .. code-block:: r > x<-c(1:3) > x [1] 1 2 3 > rbind(x) [,1] [,2] [,3] x 1 2 3 > cbind(x) x [1,] 1 [2,] 2 [3,] 3 Exercices --------- Créer les matrices ``x`` et ``y``. .. math:: x = \left(\begin{matrix} 3 & 2 \\ -1 & 1 \end{matrix}\right) \quad y = \left(\begin{matrix} 1 & 4 & 0 \\ 0 & 1 & -1 \end{matrix}\right) .. admonition:: Question Essayer de prédire le résultat des instructions suivantes:: > 2*x > x*x > x%*%x > x%*%y > t(y) > solve(x) Vérifier dans la console .. admonition:: Question Essayer de prédire le résultat des instructions suivantes:: > x[1,] > x[2,] > x[,2] > y[1,2] > y[,2:3] Vérifier dans la console Application : population urbaine -------------------------------- Pour cet exercice, utiliser les données déjà utilisées dans :ref:`l'exercice d'application sur les vecteurs` et stockées dans le fichier :download:`population.RData ` pour construire la matrice ``pop`` suivante. En deux étapes : - la première aggrège les données numériques et formate la matrice en 8 lignes (les années) et 20 colonnes (les villes) ; - la seconde définit un label pour chacune des lignes et chacune des colonnes. +----+--------+--------+--------+--------+ | | Angers |Bordeaux| |Toulouse| +----+--------+--------+--------+--------+ |1962| 115273 | 278403 | | 323724 | +----+--------+--------+--------+--------+ | | | | | | +----+--------+--------+--------+--------+ |2012| 149017 | 241287 | | 453317 | +----+--------+--------+--------+--------+ Utiliser la fonction :func:`array` pour aggréger les valeurs numériques. .. pop <- array( c(angers, bordeaux, brest, dijon, grenoble, lehavre, lemans, lille, lyon, marseille, montpellier, nantes, nice, paris, reims, rennes, saintetienne, strasbourg, toulon, toulouse), dim=c(8,20))) A cette étape les labels des lignes et des colonnes (obtenus avec les fonctions :func:`rownames` et :func:`colnames`) ne sont pas affectés. Vérifiez le. .. > rownames(pop) NULL > colnames(pop) NULL Utiliser maintenant les vecteurs ``cities`` et ``years`` pour affecter les labels des lignes et des colonnes et obtenir la matrice demandée. .. > rownames(pop) <- years > colnames(pop) <- cities .. Angers Bordeaux Brest Dijon Grenoble Le.Havre Le.Mans .. 1962 115273 278403 136104 135694 156707 187845 132181 .. 1968 128557 266662 154023 145357 161616 207150 143246 .. 1975 137591 223131 166826 151705 166037 217882 152285 .. 1982 136038 208159 156060 140942 156637 199388 147697 .. 1990 141404 210336 147956 146703 150758 195854 145502 .. 1999 151279 215363 149634 149867 153317 190905 146105 .. 2007 151108 235178 142722 151543 156793 179751 144164 .. 2012 149017 241287 139676 152071 158346 173142 143599 Exploration ........... Utiliser la fonction :func:`summary` pour afficher les statistiques élémentaires. .. > summary(pop) .. Angers Bordeaux Brest Dijon Grenoble Le.Havre Le.Mans .. Min. :115273 Min. :208159 Min. :136104 Min. :135694 Min. :150758 Min. :173142 Min. :132181 .. 1st Qu.:134168 1st Qu.:214106 1st Qu.:141960 1st Qu.:144253 1st Qu.:155807 1st Qu.:185822 1st Qu.:143511 .. Median :139498 Median :229154 Median :148795 Median :148285 Median :156750 Median :193380 Median :144833 .. Mean :138783 Mean :234815 Mean :149125 Mean :146735 Mean :157526 Mean :193990 Mean :144347 .. 3rd Qu.:149540 3rd Qu.:247631 3rd Qu.:154532 3rd Qu.:151584 3rd Qu.:159164 3rd Qu.:201328 3rd Qu.:146503 .. Max. :151279 Max. :278403 Max. :166826 Max. :152071 Max. :166037 Max. :217882 Max. :152285 - Quelles sont les villes ayant plus de 300000 habitants en 1962 ? .. > pop[c("1962"),] > 300000 Angers Bordeaux Brest Dijon Grenoble FALSE FALSE FALSE FALSE FALSE Le.Havre Le.Mans Lille Lyon Marseille FALSE FALSE FALSE TRUE TRUE Montpellier Nantes Nice Paris Reims FALSE FALSE FALSE TRUE FALSE Rennes Saint.Étienne Strasbourg Toulon Toulouse FALSE FALSE FALSE FALSE TRUE > pop[c("1962"),pop[c("1962"),] > 300000 ] Lyon Marseille Paris Toulouse 535746 778071 2790091 323724 - Pour ces mêmes villes, combien chacune a t-elle d'habitants en 1968 ? .. > pop[c("1968"),pop[c("1962"),] > 300000 ] Lyon Marseille Paris Toulouse 527800 889029 2590771 370796 - Calculer le flux migratoire entre 1962 et 1968 pour chacune des villes et identifier celles pour lesquelles il est négatif .. > d <- pop[c("1968"),] - pop[c("1962"),] > d Angers Bordeaux Brest Dijon Grenoble 13284 -11741 17919 9663 4909 Le.Havre Le.Mans Lille Lyon Marseille 19305 11065 -1401 -7946 110958 Montpellier Nantes Nice Paris Reims 43046 20196 29484 -199320 19678 Rennes Saint.Étienne Strasbourg Toulon Toulouse 28995 12912 20425 12949 47072 > d<0 Angers Bordeaux Brest Dijon Grenoble FALSE TRUE FALSE FALSE FALSE Le.Havre Le.Mans Lille Lyon Marseille FALSE FALSE TRUE TRUE FALSE Montpellier Nantes Nice Paris Reims FALSE FALSE FALSE TRUE FALSE Rennes Saint.Étienne Strasbourg Toulon Toulouse FALSE FALSE FALSE FALSE FALSE > d[d<0] Bordeaux Lille Lyon Paris -11741 -1401 -7946 -199320 - Identifier celles qui ont franchi la barre des 300.000 habitants entre 1962 et 1968 .. > pop[c("1962"),]<300000 & pop[c("1968"),]>300000 Angers Bordeaux Brest Dijon Grenoble FALSE FALSE FALSE FALSE FALSE Le.Havre Le.Mans Lille Lyon Marseille FALSE FALSE FALSE FALSE FALSE Montpellier Nantes Nice Paris Reims FALSE FALSE TRUE FALSE FALSE Rennes Saint.Étienne Strasbourg Toulon Toulouse FALSE FALSE FALSE FALSE FALSE colnames(pop)[pop[c("1962"),]<300000 & pop[c("1968"),]>300000] [1] "Nice" - Calculer l'augmentation de population dans les 20 plus grandes villes entre 1962 et 2012 .. > pop[c("2012"),] - pop[c("1962"),] Angers Bordeaux Brest Dijon Grenoble 33744 -37116 3572 16377 1639 Le.Havre Le.Mans Lille Lyon Marseille -14703 11418 -11303 -39403 74445 Montpellier Nantes Nice Paris Reims 149592 51556 50671 -549470 47037 Rennes Saint.Étienne Strasbourg Toulon Toulouse 57912 -38828 45423 3102 129593