2  Vecteurs

Les vecteurs sont l’objet de base de R et correspondent à une liste de valeurs. Leurs propriétés fondamentales sont :

2.1 Types et classes

Dans R, il existe plusieurs types fondamentaux de vecteurs et, en particulier, :

  • les nombres réels (c’est-à-dire les nombres décimaux1), par exemple 5.23 ;
  • les nombres entiers, que l’on saisi en ajoutant le suffixe L2, par exemple 4L ;
  • les chaînes de caractères (qui correspondent à du texte), que l’on saisit avec des guillemets doubles (") ou simples ('), par exemple "abc" ;
  • les valeurs logiques ou valeurs booléennes, à savoir vrai ou faux, que l’on représente avec les mots TRUE et FALSE (en majuscules3).

1 Pour rappel, R étant anglophone, le caractère utilisé pour indiqué les chiffres après la virgule est le point (.).

2 R utilise 32 bits pour représenter des nombres entiers, ce qui correspond en informatique à des entiers longs ou long integers en anglais, d’où la lettre L utilisée pour indiquer un nombre entier.

3 On peut également utiliser les raccourcis T et F. Cependant, pour une meilleure lisibilité du code, il est préférable d’utiliser les versions longues TRUE et FALSE.

En plus de ces types de base, il existe de nombreux autres types de vecteurs utilisés pour représenter toutes sortes de données, comme les facteurs (voir Chapitre 9) ou les dates (voir Chapitre 34).

La fonction class() renvoie la nature d’un vecteur tandis que la fonction typeof() indique la manière dont un vecteur est stocké de manière interne par R.

x class(x) typeof(x)
3L integer integer
5.3 numeric double
TRUE logical logical
"abc" character character
factor("a") factor integer
as.Date("2020-01-01") Date double
Table 2.1: Le type et la classe des principaux types de vecteurs
Astuce

Pour un vecteur numérique, le type est "double" car R utilise une double précision pour stocker en mémoire les nombres réels.

En interne, les facteurs sont représentés par un nombre entier auquel est attaché une étiquette, c’est pourquoi typeof() renvoie "integer".

Quand aux dates, elles sont stockées en interne sous la forme d’un nombre réel représentant le nombre de jours depuis le 1er janvier 1970, d’où le fait que typeof() renvoie "double".

2.2 Création d’un vecteur

Pour créer un vecteur, on utilisera la fonction c() en lui passant la liste des valeurs à combiner4.

4 La lettre c est un raccourci du mot anglais combine, puisque cette fonction permet de combiner des valeurs individuelles dans un vecteur unique.

taille <- c(1.88, 1.65, 1.92, 1.76, NA, 1.72)
taille
[1] 1.88 1.65 1.92 1.76   NA 1.72
sexe <- c("h", "f", "h", "f", "f", "f")
sexe
[1] "h" "f" "h" "f" "f" "f"
urbain <- c(TRUE, TRUE, FALSE, FALSE, FALSE, TRUE)
urbain
[1]  TRUE  TRUE FALSE FALSE FALSE  TRUE

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 :

x <- c(2L, 3.14, "a")
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.

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"

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 4.86 5.19 5.52

L’opérateur : est un raccourci de la fonction seq() pour créer une suite de nombres entiers. Il s’utilise ainsi :

1:5
[1] 1 2 3 4 5
24:32
[1] 24 25 26 27 28 29 30 31 32
55:43
 [1] 55 54 53 52 51 50 49 48 47 46 45 44 43

2.3 Longueur d’un vecteur

La longueur d’un vecteur correspond au nombre de valeurs qui le composent. Elle s’obtient avec length() :

length(taille)
[1] 6
length(c("a", "b"))
[1] 2

La longueur d’un vecteur vide (NULL) est zéro.

length(NULL)
[1] 0

2.4 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.

x <- c(2, 1, 3, 4)
length(x)
[1] 4
y <- c(9, 1, 2, 6, 3, 0)
length(y)
[1] 6
z <- c(x, y)
z
 [1] 2 1 3 4 9 1 2 6 3 0
length(z)
[1] 10

2.5 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 :

sexe <- c(
  Michel = "h", Anne = "f", 
  Dominique = NA, Jean = "h", 
  Claude = NA, Marie = "f"
)

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"      "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() :

anonyme <- unname(sexe)
anonyme
[1] "h" "f" NA  "h" NA  "f"

2.6 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 crochets5 ([]) ce qu’on souhaite garder ou non.

5 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 1.65 1.92 1.76   NA 1.72

Si on souhaite le premier élément du vecteur, on peut faire :

taille[1]
[1] 1.88

Si on souhaite les trois premiers éléments ou les éléments 2, 5 et 6 :

taille[1:3]
[1] 1.88 1.65 1.92
taille[c(2, 5, 6)]
[1] 1.65   NA 1.72

Si on veut le dernier élément :

taille[length(taille)]
[1] 1.72

Il est tout à fait possible de sélectionner les valeurs dans le désordre :

taille[c(5, 1, 4, 3)]
[1]   NA 1.88 1.76 1.92

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 :

taille[c(-1, -5)]
[1] 1.65 1.92 1.76 1.72

À noter, si on indique une position au-delà de la longueur du vecteur, R renverra NA. Par exemple :

taille[23:25]
[1] NA NA NA

2.7 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.

sexe["Anna"]
Anna 
 "f" 
sexe[c("Mary", "Michael", "John")]
   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…

sexe[names(sexe) != "Dom"]

… pour sélectionner tous les éléments sauf celui qui s’appelle Dom.

2.8 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" 
sexe[c(TRUE, FALSE, FALSE, TRUE, FALSE, FALSE)]
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.

urbain <- c(TRUE, TRUE, FALSE, FALSE, FALSE, TRUE)
poids <- c(80, 63, 75, 87, 82, 67)

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    Anna    Mary 
    "h"     "f"     "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 à
%in% appartient à
!= différent de
> strictement supérieur à
< strictement inférieur à
>= supérieur ou égal à
<= inférieur ou égal à
Table 2.2: Opérateurs de comparaison

Voyons tout de suite un exemple :

poids >= 80
[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 :

taille[poids >= 80]
[1] 1.88 1.76   NA

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
Table 2.3: Opérateurs logiques

Supposons que je veuille identifier les personnes pesant 80 kilogrammes ou plus et vivant en milieu urbain :

poids >= 80 & urbain
[1]  TRUE FALSE FALSE FALSE FALSE FALSE

Les résultats sont différents si je souhaite isoler les personnes pesant 80 kilogrammes ou plus ou vivant milieu urbain :

poids >= 80 | urbain
[1]  TRUE  TRUE FALSE  TRUE  TRUE  TRUE
Comparaison et valeur manquante

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 1.65 1.92 1.76   NA 1.72
taille > 1.8
[1]  TRUE FALSE  TRUE FALSE    NA FALSE

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 FALSE FALSE FALSE  TRUE FALSE

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 1.65 1.92 1.76   NA 1.72
poids
[1] 80 63 75 87 82 67
poids[taille > 1.8]
[1] 80 75 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 :

poids[taille > 1.8 & !is.na(taille)]
[1] 80 75

2.9 Assignation par indexation

L’indexation peut être combinée avec l’assignation (opérateur <-) pour modifier seulement certaines parties d’un vecteur. Ceci fonctionne pour les différents types d’indexation évoqués précédemment.

v <- 1:5
v
[1] 1 2 3 4 5
v[1] <- 3
v
[1] 3 2 3 4 5
sexe["Alex"] <- "non-binaire"
sexe
      Michael          Anna           Dom          John          Alex 
          "h"           "f"            NA           "h" "non-binaire" 
         Mary 
          "f" 

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 :

sexe[c(1,3,4)] <- c("Homme", "Homme", "Homme")
sexe[c(1,3,4)] <- "Homme"

L’assignation par indexation peut aussi être utilisée pour ajouter une ou plusieurs valeurs à un vecteur :

length(sexe)
[1] 6
sexe[7] <- "f"
sexe
      Michael          Anna           Dom          John          Alex 
      "Homme"           "f"       "Homme"       "Homme" "non-binaire" 
         Mary               
          "f"           "f" 
length(sexe)
[1] 7

2.10 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 fonction length() 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 et FALSE 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 (<-).

2.11 webin-R

On pourra également se référer au webin-R #02 (les bases du langage R) sur YouTube.