Vecteurs, indexation et assignation
Ce chapitre est évoqué dans le webin-R #02 (les bases du langage R) sur YouTube.
Nous allons reprendre plusieurs éléments de base du langage R que nous avons déjà abordés mais de manière plus formelle. Une bonne compréhension des bases du langage, bien qu’un peu ardue de prime abord, permet de comprendre le sens des commandes qu’on utilise et de pleinement exploiter la puissance que R offre en matière de manipulation de données.
Dans ce chapitre, nous reviendrons sur les vecteurs, tandis que les listes et les tableaux de données seront abordés dans un chapitre dédié.
Présentation des vecteurs
Les vecteurs sont l’un des objets de base de R et correspondent à une liste de valeurs
. Leurs propriétés fondamentales sont :
- les vecteurs sont unidimensionnels (i.e. ce sont des objets à une seule dimension, à la différence d’une matrice par exemple) ;
- toutes les valeurs d’un vecteur sont d’un seul et même type ;
- les vecteurs ont une longueur qui correspond au nombre de valeurs contenues dans le vecteur.
Les principaux types de vecteurs
Dans R, il existe quatre types fondamentaux de vecteurs :
- les nombres réels (c’est-à-dire les nombres décimaux que nous utilisons au quotidien),
- les nombres entiers,
- les chaînes de caractères (qui correspondent à du texte) et
- les valeurs logiques ou valeurs booléennes, à savoir
vrai
oufaux
.
Pour connaître la nature d’un objet, le plus simple est d’utiliser la fonction class
. Par exemple :
class(12.5)
[1] "numeric"
La réponse "numeric"
nous indique qu’il s’agit d’un nombre réel. Parfois, vous pourrez rencontrer le terme "double"
qui désigne également les nombres réels. Notez que R étant anglophone, la décimale est indiquée avec un point (.
) et non avec une virgule comme c’est l’usage en français.
Essayons avec un nombre entier :
class(3)
[1] "numeric"
Sous R, lorsqu’on tape un nombre sans autre précision, il est considéré par défaut comme un nombre réel. Pour indiquer spécifiquement qu’on veut un nombre entier, il faut rajouter le suffixe L
:
class(3L)
[1] "integer"
Au quotidien, il arrive rarement d’avoir à utiliser ce suffixe, mais il est toujours bon de le connaître au cas où vous le rencontriez dans des manuels ou des exemples de code.
Pour saisir une chaîne de caractères, on aura recours aux doubles guillemets droits ("
) :
class("abc")
[1] "character"
Il est également possible d’utiliser des guillemets simples ('
), dès lors qu’on utilise bien le même type de guillemets pour indiquer le début et la fin de la chaîne de caractères (par exemple 'abc'
).
Enfin, les valeurs logiques s’indiquent avec TRUE
pour vrai et FALSE
pour faux. Il est aussi possible d’utiliser les raccourcis T
et F
. Attention à bien utiliser les majuscules, R étant sensible à la casse.
class(TRUE)
[1] "logical"
En résumé, les classes R des quatre types fondamentaux de vecteur sont :
Exemple | Classe R | Type |
---|---|---|
5L |
integer | nombre entier |
3.14 |
numeric | nombre réel |
"abcd" |
character | chaîne de caractères |
TRUE |
logical | booléenne |
En plus des types de base, il existe de nombreuses autres classes de vecteurs dans R que nous aborderons ultérieurement dans d’autres chapitres. Les plus courantes sont :
Classe R | Type |
---|---|
factor | facteur |
labelled | vecteur labellisé |
Date | date |
POSIXct | date et heure |
Création
La fonction c
Pour créer un vecteur, on utilisera la fonction c
, la lettre c
étant un raccourci du mot anglais combine puisque cette fonction permet de combiner des valeurs individuelles dans un vecteur unique. Il suffit de lui passer la liste des valeurs à combiner :
<- c(1.88, 1.65, 1.92, 1.76)
taille taille
[1] 1.88 1.65 1.92 1.76
class(taille)
[1] "numeric"
<- c("h", "f", "h", "f")
sexe sexe
[1] "h" "f" "h" "f"
class(sexe)
[1] "character"
<- c(TRUE, TRUE, FALSE, FALSE)
urbain urbain
[1] TRUE TRUE FALSE FALSE
class(urbain)
[1] "logical"
Nous l’avons vu, toutes les valeurs d’un vecteur doivent obligatoirement être du même type. Dès lors, si on essaie de combiner des valeurs de différents types, R essaiera de les convertir au mieux. Par exemple :
<- c(2L, 3.14, "a")
x x
[1] "2" "3.14" "a"
class(x)
[1] "character"
Dans le cas présent, toutes les valeurs ont été converties en chaînes de caractères.
La fonction rep
Dans certaines situations, on peut avoir besoin de créer un vecteur d’une certaine longueur mais dont toutes les valeurs sont identiques. Cela se réalise facilement avec rep
à qui on indiquera la valeur à répéter puis le nombre de répétitions :
rep(2, 10)
[1] 2 2 2 2 2 2 2 2 2 2
On peut aussi lui indiquer plusieurs valeurs qui seront alors répétées en boucle :
rep(c("a", "b"), 3)
[1] "a" "b" "a" "b" "a" "b"
La fonction seq
Dans d’autres situations, on peut avoir besoin de créer un vecteur contenant une suite de valeurs, ce qui se réalise aisément avec seq
à qui on précisera les arguments from
(point de départ), to
(point d’arrivée) et by
(pas). Quelques exemples valent mieux qu’un long discours :
seq(1, 10)
[1] 1 2 3 4 5 6 7 8 9 10
seq(5, 17, by = 2)
[1] 5 7 9 11 13 15 17
seq(10, 0)
[1] 10 9 8 7 6 5 4 3 2 1 0
seq(100, 10, by = -10)
[1] 100 90 80 70 60 50 40 30 20 10
seq(1.23, 5.67, by = 0.33)
[1] 1.23 1.56 1.89 2.22 2.55 2.88 3.21 3.54 3.87 4.20 4.53
[12] 4.86 5.19 5.52
Longueur d’un vecteur
Un vecteur dispose donc d’une longueur qui correspond au nombre de valeurs qui le composent. Elle s’obtient avec length
:
length(taille)
[1] 4
length(c("a", "b"))
[1] 2
Il est possible de faire un vecteur de longueur nulle avec c()
. Bien évidemment sa longueur est zéro.
length(c())
[1] 0
Quelques vecteurs remarquables
R fournit quelques vecteurs particuliers qui sont directement accessibles :
LETTERS
: les 26 lettres de l’alphabet en majusculesletters
: les 26 lettres de l’alphabet en minusculesmonth.name
: les noms des 12 mois de l’année en anglaismonth.abb
: la version abrégée des 12 mois en anglaispi
: la constante mathématique π
LETTERS
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N"
[15] "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
letters
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n"
[15] "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
length(letters)
[1] 26
month.name
[1] "January" "February" "March" "April"
[5] "May" "June" "July" "August"
[9] "September" "October" "November" "December"
month.abb
[1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep"
[10] "Oct" "Nov" "Dec"
length(month.abb)
[1] 12
pi
[1] 3.141593
length(pi)
[1] 1
Combiner des vecteurs
Pour combiner des vecteurs, rien de plus simple. Il suffit d’utiliser c
! Les valeurs des différents vecteurs seront mises bout à bout pour créer un unique vecteur.
<- c(2, 1, 3, 4)
x length(x)
[1] 4
<- c(9, 1, 2, 6, 3, 0)
y length(y)
[1] 6
<- c(x, y)
z z
[1] 2 1 3 4 9 1 2 6 3 0
length(z)
[1] 10
<- c(letters, LETTERS)
min_maj min_maj
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n"
[15] "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" "A" "B"
[29] "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P"
[43] "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
length(min_maj)
[1] 52
Valeurs manquantes
Lorsqu’on travaille avec des données d’enquête, il est fréquent que certaines données soient manquantes, en raison d’un refus du participant de répondre à une question donnée ou d’un oubli ou d’un dysfonctionnement du matériel de mesure, etc.
Une valeur manquante s’indique sous R avec NA
(pour not available). Cette valeur peut s’appliquer à n’importe quel type de vecteur, qu’il soit numérique, textuel ou logique.
<- c(1.88, NA, 1.65, 1.92, 1.76, NA)
taille <- c("h", "f", NA, "h", NA, "f") sexe
Les valeurs manquantes sont prises en compte dans le calcul de la longueur du vecteur.
length(taille)
[1] 6
Il ne faut pas confondre NA
avec un autre objet qu’on rencontre sous R qui s’appelle NULL
et qui représente l’objet vide
. NULL
ne contient absolument rien. La différence se comprend mieux lorsqu’on essaie de combiner ces objets :
c(NULL, NULL, NULL)
NULL
length(c(NULL, NULL, NULL))
[1] 0
On peut combiner NULL
avec NULL
, du vide plus du vide renverra toujours du vide dont la dimension est égale à zéro.
c(NA, NA, NA)
[1] NA NA NA
length(c(NA, NA, NA))
[1] 3
Par contre, un vecteur composé de trois valeurs manquantes a une longueur de 3, même si toutes ses valeurs sont manquantes.
Indexation par position
L’indexation est l’une des fonctionnalités les plus puissantes mais aussi les plus difficiles à maîtriser de R. Il s’agit d’opérations permettant de sélectionner des sous-ensembles de valeurs en fonction de différents critères. Il existe trois types d’indexation : (i) l’indexation par position, (ii) l’indexation par nom et (iii) l’indexation par condition. Le principe est toujours le même : on indique entre crochets ([]
) ce qu’on souhaite garder ou non.
Pour rappel, les crochets s’obtiennent sur un clavier français de type PC en appuyant sur la touche Alt Gr et la touche ( ou ).
Commençons par l’indexation par position encore appelée indexation directe. Ce mode le plus simple d’indexation consiste à indiquer la position des éléments à conserver.
Reprenons notre vecteur taille
:
taille
[1] 1.88 NA 1.65 1.92 1.76 NA
Si on souhaite le premier élément du vecteur, on peut faire :
1] taille[
[1] 1.88
Si on souhaite les trois premiers éléments ou les éléments 2, 5 et 6 :
1:3] taille[
[1] 1.88 NA 1.65
c(2, 5, 6)] taille[
[1] NA 1.76 NA
Si on veut le dernier élément :
length(taille)] taille[
[1] NA
Il est tout à fait possible de sélectionner les valeurs dans le désordre :
c(5, 1, 4, 3)] taille[
[1] 1.76 1.88 1.92 1.65
Dans le cadre de l’indexation par position, il est également possible de spécifier des nombres négatifs, auquel cas cela signifiera toutes les valeurs sauf celles-là
. Par exemple :
c(-1, -5)] taille[
[1] NA 1.65 1.92 NA
À noter, si on indique une position au-delà de la longueur du vecteur, R renverra NA
. Par exemple :
23:25] taille[
[1] NA NA NA
Des vecteurs nommés
Les différentes valeurs d’un vecteur peuvent être nommées. Une première manière de nommer les éléments d’un vecteur est de le faire à sa création :
<- c(Michel = "h", Anne = "f", Dominique = NA, Jean = "h", Claude = NA, Marie = "f") sexe
Lorsqu’on affiche le vecteur, la présentation change quelque peu.
sexe
Michel Anne Dominique Jean Claude Marie
"h" "f" NA "h" NA "f"
La liste des noms s’obtient avec names
.
names(sexe)
[1] "Michel" "Anne" "Dominique" "Jean"
[5] "Claude" "Marie"
Pour ajouter ou modifier les noms d’un vecteur, on doit attribuer un nouveau vecteur de noms :
names(sexe) <- c("Michael", "Anna", "Dom", "John", "Alex", "Mary")
sexe
Michael Anna Dom John Alex Mary
"h" "f" NA "h" NA "f"
Pour supprimer tous les noms, il y a la fonction unname
:
<- unname(sexe)
anonyme anonyme
[1] "h" "f" NA "h" NA "f"
Indexation par nom
Lorsqu’un vecteur est nommé, il est dès lors possible d’accéder à ses valeurs à partir de leur nom. Il s’agit de l’indexation par nom.
"Anna"] sexe[
Anna
"f"
c("Mary", "Michael", "John")] sexe[
Mary Michael John
"f" "h" "h"
Par contre il n’est pas possible d’utiliser l’opérateur -
comme pour l’indexation directe. Pour exclure un élément en fonction de son nom, on doit utiliser une autre forme d’indexation, l’indexation par condition, expliquée dans la section suivante. On peut ainsi faire…
names(sexe) != "Dom"] sexe[
… pour sélectionner tous les éléments sauf celui qui s’appelle Dom
.
Indexation par condition
L’indexation par condition consiste à fournir un vecteur logique indiquant si chaque élément doit être inclus (si TRUE
) ou exclu (si FALSE
). Par exemple :
sexe
Michael Anna Dom John Alex Mary
"h" "f" NA "h" NA "f"
c(TRUE, FALSE, FALSE, TRUE, FALSE, FALSE)] sexe[
Michael John
"h" "h"
Écrire manuellement une telle condition n’est pas très pratique à l’usage. Mais supposons que nous ayons également à notre disposition les deux vecteurs suivants, également de longueur 6.
<- c(TRUE, FALSE, FALSE, FALSE, TRUE, TRUE)
urbain <- c(80, 63, 75, 87, 82, 67) poids
Le vecteur urbain
est un vecteur logique. On peut directement l’utiliser pour avoir le sexe des enquêtés habitant en milieu urbain :
sexe[urbain]
Michael Alex Mary
"h" NA "f"
Supposons qu’on souhaite maintenant avoir la taille des individus pesant 80 kilogrammes ou plus. Nous pouvons effectuer une comparaison à l’aide des opérateurs de comparaison suivants :
Opérateur de comparaison | Signification |
---|---|
== |
égal à |
!= |
différent de |
> |
strictement supérieur à |
< |
strictement inférieur à |
>= |
supérieur ou égal à |
<= |
inférieur ou égal à |
Voyons tout de suite un exemple :
>= 80 poids
[1] TRUE FALSE FALSE TRUE TRUE FALSE
Que s’est-il passé ? Nous avons fourni à R une condition et il nous a renvoyé un vecteur logique avec autant d’éléments qu’il y a d’observations et dont la valeur est TRUE
si la condition est remplie et FALSE
dans les autres cas. Nous pouvons alors utiliser ce vecteur logique pour obtenir la taille des participants pesant 80 kilogrammes ou plus :
>= 80] taille[poids
[1] 1.88 1.92 1.76
On peut combiner ou modifier des conditions à l’aide des opérateurs logiques habituels :
Opérateur logique | Signification |
---|---|
& |
et logique |
| |
ou logique |
! |
négation logique |
Comment les utilise-t-on ? Voyons tout de suite un exemple. Supposons que je veuille identifier les personnes pesant 80 kilogrammes ou plus et vivant en milieu urbain :
>= 80 & urbain poids
[1] TRUE FALSE FALSE FALSE TRUE FALSE
Les résultats sont différents si je souhaite isoler les personnes pesant 80 kilogrammes ou plus ou vivant milieu urbain :
>= 80 | urbain poids
[1] TRUE FALSE FALSE TRUE TRUE TRUE
Une remarque importante : quand l’un des termes d’une condition comporte une valeur manquante (NA
), le résultat de cette condition n’est pas toujours TRUE
ou FALSE
, il peut aussi être à son tour une valeur manquante.
taille
[1] 1.88 NA 1.65 1.92 1.76 NA
> 1.8 taille
[1] TRUE NA FALSE TRUE FALSE NA
On voit que le test NA > 1.8
ne renvoie ni vrai ni faux, mais NA
.
Une autre conséquence importante de ce comportement est qu’on ne peut pas utiliser l’opérateur l’expression == NA
pour tester la présence de valeurs manquantes. On utilisera à la place la fonction ad hoc is.na
:
is.na(taille > 1.8)
[1] FALSE TRUE FALSE FALSE FALSE TRUE
Pour compliquer encore un peu le tout, lorsqu’on utilise une condition pour l’indexation, si la condition renvoie NA
, R ne sélectionne pas l’élément mais retourne quand même la valeur NA
. Ceci a donc des conséquences sur le résultat d’une indexation par comparaison.
Par exemple si je cherche à connaître le poids des personnes mesurant 1,80 mètre ou plus :
taille
[1] 1.88 NA 1.65 1.92 1.76 NA
poids
[1] 80 63 75 87 82 67
> 1.8] poids[taille
[1] 80 NA 87 NA
Les éléments pour lesquels la taille n’est pas connue ont été transformés en NA
, ce qui n’influera pas le calcul d’une moyenne. Par contre, lorsqu’on utilisera assignation et indexation ensemble, cela peut créer des problèmes. Il est donc préférable lorsqu’on a des valeurs manquantes de les exclure ainsi :
> 1.8 & !is.na(taille)] poids[taille
[1] 80 87
Pour plus de détails sur les conditions et le calcul logique dans R, on pourra se référer au chapitre dédié.
Assignation par indexation
Dans tous les exemples précédents, on a utilisé l’indexation pour extraire une partie d’un vecteur, en plaçant l’opération d’indexation à droite de l’opérateur <-
.
Mais l’indexation peut également être placée à gauche de cet opérateur d’assignation. Dans ce cas, les éléments sélectionnés par l’indexation sont alors remplacés par les valeurs indiquées à droite de l’opérateur <-
.
Prenons donc un exemple simple :
<- 1:5
v v
[1] 1 2 3 4 5
1] <- 3
v[ v
[1] 3 2 3 4 5
Cette fois, au lieu d’utiliser quelque chose comme x <- v[1]
, qui aurait placé la valeur du premier élément de v
dans x
, on a utilisé v[1] <- 3
, ce qui a mis à jour le premier élément de v
avec la valeur 3. Ceci fonctionne également pour les différents types d’indexation évoqués précédemment :
"Alex"] <- "f" sexe[
Enfin on peut modifier plusieurs éléments d’un seul coup soit en fournissant un vecteur, soit en profitant du mécanisme de recyclage. Les deux commandes suivantes sont ainsi rigoureusement équivalentes :
c(1, 3, 4)] <- c("Homme", "Homme", "Homme")
sexe[c(1, 3, 4)] <- "Homme" sexe[
L’assignation par indexation peut aussi être utilisée pour ajouter une ou plusieurs valeurs à un vecteur :
length(sexe)
[1] 6
7] <- "f"
sexe[ sexe
Michael Anna Dom John Alex Mary
"Homme" "f" "Homme" "Homme" "f" "f" "f"
length(sexe)
[1] 7
On commence à voir comment l’utilisation de l’indexation par conditions et de l’assignation va nous permettre de faire des recodages (que nous aborderons plus en détail dans un chapitre dédié).
En résumé
- Un vecteur est un objet unidimensionnel contenant une liste de valeurs qui sont toutes du même type (entières, numériques, textuelles ou logiques).
- La fonction
class
permet de connaître le type du vecteur et la fonctionlength
sa longueur, c’est-à-dire son nombre d’éléments. - La fonction
c
sert à créer et à combiner des vecteurs. - Les valeurs manquantes sont représentées avec
NA
. - Un vecteur peut être nommé, c’est-à-dire qu’un nom textuel a été associé à chaque élément. Cela peut se faire lors de sa création ou avec la fonction
names
. - L’indexation consiste à extraire certains éléments d’un vecteur. Pour cela, on indique ce qu’on souhaite extraire entre crochets (
[]
) juste après le nom du vecteur. Le type d’indexation dépend du type d’information transmise. - S’il s’agit de nombres entiers, c’est l’indexation par position : les nombres représentent la position dans le vecteur des éléments qu’on souhaite extraire. Un nombre négatif s’interprète comme
tous les éléments sauf celui-là
. - Si on indique des chaînes de caractères, c’est l’indexation par nom : on indique le nom des éléments qu’on souhaite extraire. Cette forme d’indexation ne fonctionne que si le vecteur est nommé.
- Si on transmet des valeurs logiques, le plus souvent sous la forme d’une condition, c’est l’indexation par condition :
TRUE
indique les éléments à extraire etFALSE
les éléments à exclure. Il faut être vigilant aux valeurs manquantes (NA
) dans ce cas précis. - Enfin, il est possible de ne modifier que certains éléments d’un vecteur en ayant recours à la fois à l’indexation (
[]
) et à l’assignation (<-
).