3 Les vecteurs

Les vecteurs sont la structure de données fondamentale dans R. Le terme «structure de données» fait référence à la manière dont les données sont stockées et organisées par R. En plus des vecteurs, les quatre structures les plus souvent utilisées sont: les facteurs, les matrices, les listes et les data frames (tableau des données). Chacune de ces structures/objets sera traitée séparément dans les chapitres suivants.

3.1 Les trois types de vecteurs

Les vecteurs stockent une liste ordonnée d’éléments, tous du même type: numérique, caractère ou logique. Un objet dont tous les éléments sont de même type est appelé simple ou atomique (atomic object, en anglais).

Numérique

Imaginons que nous avons interrogé dix personnes au hasard dans la rue et que nous avons relevé pour chacune d’elle sa taille (en centimètre). On peut stocker cette information dans un seul objet à l’aide de la fonction c() qui permet simplement de combiner ces arguments.

taille <- c(167, 192, 173, 174, 172, 167, 171, 185, 163, 170) # mesures en cm
taille
 [1] 167 192 173 174 172 167 171 185 163 170

En réalité, R distingue deux types de numeric: double (ou dbl) pour réelle et integer (ou int) pour entier, mais cette distinction n’a pas beaucoup d’importance. En R, par défaut, un numeric est un double.

Chaîne de caractères

Imaginons que nous avons aussi relevé le nom de chaque personne.

nom <- c("Benjamin", "Hugo", "Emma", "Alex", "Tom", "Axel", "Alice", "Martin", "Robin", "Enzo")
nom
 [1] "Benjamin" "Hugo"     "Emma"     "Alex"     "Tom"      "Axel"    
 [7] "Alice"    "Martin"   "Robin"    "Enzo"    

Logique

Supposons que nous savons aussi si un individu est fumeur ou pas. Puisqu’il s’agit d’une quantité binaire (vrai ou faux), on peut utiliser un vecteur logique pour stocker cette information:

fum <- c(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE)
fum
 [1] FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE

Notez qu’il est possible d’utliser T et F comme abréviations de TRUE et FALSE, respectivement.

c(T, F)
[1]  TRUE FALSE

Mais on recommande de ne pas utiliser cette abréviation, au risque d’entraîner certaines confusions.

3.2 Les carctériqtiques d’un vecteur

Nous pouvons examiner la structure d’un vecteur avec la fonction str(). Cette fonction est essentielle à connaître et peut s’appliquer à n’importe quel objet R (pas uniquement les vecteurs). Elle indique la nature de l’objet ainsi qu’un aperçu de ce qui est stocker dedans.

str(taille)
str(nom)
str(fum)
 num [1:10] 167 192 173 174 172 167 171 185 163 170
 chr [1:10] "Benjamin" "Hugo" "Emma" "Alex" "Tom" "Axel" "Alice" "Martin" ...
 logi [1:10] FALSE FALSE TRUE FALSE FALSE TRUE ...

Dans la sortie ci-dessus, on peut voir que la fonction str() affiche bien la nature de chaque vecteur (num = numeric, chr = character, et logi = logical).

Un autre caractéristique important de chaque vecteur est sa longueur que nous pouvons obtenir grâce à la fonction length().

length(taille)
[1] 10

À ce propos, notez que, en R, un scalaire n’est rien d’autre qu’un vecteur de longueur 1. Ainsi, les deux écritures x <- 1 et x <- c(1) sont équivalentes. De même x <- "Benjamin" et x <- c("Benjamin") sont équivalentes.

Pour mieux visualiser à quoi correspond les valeurs stockées dans un vecteur, on peut attribuer des noms aux différents éléments/composantes. Voici une illustration.

person1 <- c(22, 1.84, 1348)
names(person1) <- c("age", "height", "zipcode")
person1
    age  height zipcode 
  22.00    1.84 1348.00 

Pour un vecteur nommé, l’affichage de la fonction str() est un peu différent.

str(person1)
 Named num [1:3] 22 1.84 1348
 - attr(*, "names")= chr [1:3] "age" "height" "zipcode"

On peut aussi nommer les éléments d’un vecteur au moment de sa création, comme ceci.

person1 <- c(age = 22, height = 1.84, zipcode = 1348)

Finalement, sachez qu’il existe d’autres fonctions pour cerner les caractéristiques d’un objet en R comme par exemple les fonctions typeof() et attributes().

typeof(taille)
attributes(taille)
[1] "double"
NULL

3.3 R est un langage vectoriel

R peut effectuer les opérations mathématiques classiques directement sur les vecteurs. Les opérations entre vecteurs se font membre à membre.

taille + c(1, 2, 3, 4, 5, 6, 7, 8, 9, 40)
taille^2
log(taille)
poids <- c(86, 74, 83, 50, 78, 66, 66, 51, 50, 55) # mesures en Kg
imc <- poids / (taille / 100)^2    # indice de masse corporelle (Kg/m^2)
imc
 [1] 168 194 176 178 177 173 178 193 172 210
 [1] 27889 36864 29929 30276 29584 27889 29241 34225 26569 28900
 [1] 5.12 5.26 5.15 5.16 5.15 5.12 5.14 5.22 5.09 5.14
 [1] 30.8 20.1 27.7 16.5 26.4 23.7 22.6 14.9 18.8 19.0

Si les vecteurs intervenant dans une opération ne sont pas de mêmes longueurs, la règle de recyclage s’applique. R automatiquement recycle l’objet le plus court assez de fois pour arriver à un objet de longueur égale à l’objet le plus long. Voici deux exemples.

taille + 20
taille + c(0, 20)
 [1] 187 212 193 194 192 187 191 205 183 190
 [1] 167 212 173 194 172 187 171 205 163 190

Si la longueur du vecteur le plus long n’est pas un multiple du plus court, un Warning est donné :

taille + c(0, 20, 1)
Warning in taille + c(0, 20, 1): longer object length is not a multiple of
shorter object length
 [1] 167 212 174 174 192 168 171 205 164 170

Cette sortie est la même que celle qu’on obtiendrait si on tape taille + c(0, 20, 1, 0, 20, 1, 0, 20, 1, 0).

3.4 Combiner des vecteurs

Imaginons que nous avons interrogé 10 autres personnes et récolté leurs tailles. Dans ce cas, il est naturel de vouloir combiner les deux échantillons dans un seul et même vecteur. Cette opération peut se faire aussi à l’aide de la fonction c().

taille1 <- taille
taille2 <- c(126, 177, 159, 143, 161, 180, 169, 159, 185, 160)
Taille <- c(taille1, taille2)
Taille
 [1] 167 192 173 174 172 167 171 185 163 170 126 177 159 143 161 180 169 159 185
[20] 160

La même opération peut être effectuée comme suite.

Taille <- c(taille, 126, 177, 159, 143, 161, 180, 169, 159, 185, 160)

Note
R distingue les majuscules et les minuscules. Ainsi, taille, Taille et taiLle sont trois objets différents.

Conversion de types

Rappelons-nous que tous les éléments d’un vecteur doivent être du même type. Mais que se passe-t-il si nous combinons des objets de type différent ? Examinons les exemples suivants.

c(112, TRUE, FALSE)
c(112, "Ben")
c("Ben", TRUE, FALSE)
[1] 112   1   0
[1] "112" "Ben"
[1] "Ben"   "TRUE"  "FALSE"

On voit que R convertit automatiquement les éléments d’un vecteur pour qu’ils soient tous de mêmes types. Pour cela, il utilise la règle (symbolique) suivante.
\[ logique -> numérique -> caractère \]

càd. R transforme un objet logique en un numérique (FALSE devient 0 et TRUE devient 1) et un numérique en un caractère (1 devient "1", par exemple). Les caractères l’emportent toujours sur le reste.

Aussi, lorsqu’il s’agit d’effectuer des opérations mathématiques, R transforme automatiquement un objet logique en numérique.

c(FALSE, FALSE, TRUE, TRUE) + c(0, 1, 2, 3)
exp(c(FALSE, FALSE, TRUE, TRUE))
[1] 0 1 3 4
[1] 1.00 1.00 2.72 2.72

Il existe des fonctions, de type as.*(), pour réaliser des conversions de façon explicite. Voici un exemple

as.character(c(0, 1, 2, 3, 4))
[1] "0" "1" "2" "3" "4"
as.numeric(c("0", "1", "2", "3", "4", "a"))
Warning: NAs introduced by coercion
[1]  0  1  2  3  4 NA

Comme vous pourrez le constater ci-dessus, R retourne un NA (Not Available), pour indiquer une valeur manquante.
Les NA sont typiquement utilisés pour signaler une information non-disponible.
Par exemple, imaginez que la deuxième personne interrogée lors de notre enquête refuse de communiquer sa taille. Nous pouvons enregistrer cette information dans R comme ceci.

tailes <- c(167, NA, 173, 174, 172, 167, 171, 185, 163, 170)
tailes
 [1] 167  NA 173 174 172 167 171 185 163 170

Remarquez que NA n’est pas la même chose que NaN qui, pour rappelle, représente le résultat d’une opération numérique non défini (par exemple 0/0).

3.5 Opérateurs logiques et opérateurs de comparaison

Pour agir sur les vecteurs, R propose, en plus des opérateurs arithmétiques classiques (+, -, *, …), deux autres types d’opérateurs : les opérateurs logiques qui s’appliquent sur les vecteurs logiques et les opérateurs de comparaison qui s’appliquent sur tout type d’objets.

Opérateurs logiques

Pour agir sur les vecteurs logiques, R propose un certain nombre d’opérateurs dont voici les plus utilisés en pratique.

Opérateur logique Signification
& et
| ou
! négation

Voici un exemple.

x <- c(FALSE, TRUE, FALSE)
y <- c(FALSE, TRUE, TRUE)
x & y
x | y
!x
[1] FALSE  TRUE FALSE
[1] FALSE  TRUE  TRUE
[1]  TRUE FALSE  TRUE

Opérateurs de comparaison

Comme leur nom l’indique, ces opérateurs sont utiles pour comparer deux vecteurs.

Opérateur de comparaison Signification
== égal à
!= différent de
> strictement supérieur à
< strictement inférieur à
>= supérieur ou égal à
<= inférieur ou égal à

Voici deux exemples.

x <- c(1, 3, -1, 0)
y <- c(1, 0, 3, 0)
x >= 0
x == y
x != y
x > y
[1]  TRUE  TRUE FALSE  TRUE
[1]  TRUE FALSE FALSE  TRUE
[1] FALSE  TRUE  TRUE FALSE
[1] FALSE  TRUE FALSE FALSE
z <- c("D", "B", "C")
w <- c("A", "B", "E")
z <= w
[1] FALSE  TRUE  TRUE

On peut évidemment combiner les deux opérateurs (logiques et de comparaison) dans la même expression.

x <- c(1, 3, -1, 0)
y <- c(1, 0, 3, 0)
(x >= 0) & (x < 3) # trouves les éléments de x dans [0,3)
(x == y) | (x > y) # équivalent à écrire x >= y
[1]  TRUE FALSE FALSE  TRUE
[1]  TRUE  TRUE FALSE  TRUE

Astuce: Comparer les nombres

Lors de test d’égalité entre des nombres, il arrive que R affiche FALSE alors qu’il s’agit bel et bien de nombres identiques !

0.1 + 0.2 == 0.3
[1] FALSE

La raison est que, en system binaire (utilisé par R), les deux côtés de l’opérateur == ont une écriture différente.

print(0.1 + 0.2, digits = 20)
print(0.3, digits = 20)
[1] 0.30000000000000004441
[1] 0.2999999999999999889

Pour éviter ce type d’erreur, il est conseillé d’arrondir les nombres avant de les comparer

round(0.1 + 0.2, 10) == 0.3
[1] TRUE

ou d’utiliser la fonction all.equal().

all.equal(0.1 + 0.2, 0.3)
[1] TRUE

3.6 Accéder aux éléments d’un vecteur

Le but recherché ici est de pouvoir accéder, remplacer, modifier ou encore supprimer certains éléments d’un vecteur. Pour cela on utilise ce qu’on appelle l’indexation (ou sélection). Une indexation peut être numérique (appelé aussi indexation par position), par nom, ou logiques. Dans les trois cas, on utilisera les crochets [ ] pour indiquer le ou les éléments à choisir ou à exclure.

Indexation numérique

Il s’agit de faire suivre le nom du vecteur de crochets contenant la position/numéro de(s) élément(s) (in)désiré(s). Voici quelques exemples

taille <- c(167, 192, 173, 174, 172, 167, 171, 185, 163, 170)
taille[1]          # extraire le premier élément
taille[10]         # dernier élément
taille[c(1, 5)]    # premier et cinquième
taille[-c(1, 5)]   # tous sauf premier et cinquième
[1] 167
[1] 170
[1] 167 172
[1] 192 173 174 167 171 185 163 170

La composition d’un vecteur n’est pas altérée lors de l’indexation, mais on peut se servir de cette dernière pour introduire des modifications dans le vecteur. Voici un exemple.

taille <- c(167, 192, 173, 174, 172, 167, 171, 185, 163, 170)
taille[1] <- 175 # modifier le 1er élément
taille[c(3, 10)] <- c(168, 170) # modifier le 3e et 10e élément
taille[11] <- 176  # ajouter un nouveau élément et le placer 11e
taille <- c(taille, 177) # ajouter un nouveau élément à la fin
taille <- taille[-2] # supprimer le 2e élément
taille
 [1] 175 168 174 172 167 171 185 163 170 176 177

Parfois, il est utile de créer un vecteur vide et de la remplir par la suite (au fur et à mesure qu’on obtient des informations, par exemple).

x <- c()
x[1] <- 2
x[3] <- 22
x
[1]  2 NA 22

Indexation par nom

Dans le cas d’un vecteur nommé, on peut aussi utiliser les noms pour extraire ou modifier certains éléments.

person1 <- c(age = 22, height = 1.84, zipcode = 1348)
person1[c("zipcode", "age")]
zipcode     age 
   1348      22 

Indexation logique

On peut aussi accéder à des éléments d’un vecteur en faisant suivre le nom du vecteur de crochets contenant un vecteur logique.

Par exemple, supposons que l’on souhaite savoir le nom des fumeurs dans notre échantillon.

nom <- c("Benjamin", "Hugo", "Emma", "Alex", "Tom", "Axel", "Alice", "Martin", "Robin", "Enzo")
fum <- c(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE)
nom[fum]
[1] "Emma" "Axel" "Enzo"

Comme vous pouvez le voir, nous n’obtenons que les éléments 3, 6, et 10 de nom, car seuls ces derniers contiennent un TRUE dans le vecteur logique fum. Les deux vecteurs (à indexer (ici nom) et le vecteur logique (ici fum)) doivent être de même longueur, sinon le vecteur logique sera recyclé.

nom[c(TRUE, FALSE, TRUE)]
[1] "Benjamin" "Emma"     "Alex"     "Axel"     "Alice"    "Robin"    "Enzo"    

Voici d’autres exemples où l’indexation logique s’avère très utile.

nom <- c("Benjamin", "Hugo", "Emma", "Alex", "Tom", "Axel", "Alice", "Martin", "Robin", "Enzo")
taille <- c(167, 192, 173, 174, 172, 167, 171, 185, 163, 170)
nom[taille == 167]                # noms des personnes dont la taille est de 167 cm.
nom[taille >= 172 & taille < 180] # noms des personnes dont la taille est dans [172,180).
nom[taille >= 172 & !fum]         # taille >= 172 et non fumeur
[1] "Benjamin" "Axel"    
[1] "Emma" "Alex" "Tom" 
[1] "Hugo"   "Alex"   "Tom"    "Martin"

3.7 Quelques fonctions usuelles

Nous allons lister ici une série de fonctions/exmples très fréquemment utilisé en pratique pour créer ou manipuler les vecteurs.

Créer des séquences régulières

Il y a plusieurs façons pour créer des séries numériques en R. Voici un aperçu.

1:10                       # 1 à 10, par pas de 1
seq(1, 10)                 # 1 à 10, par pas de 1
seq(1, 10, by = 2.25)      # 1 à 10, par pas de 2.25
seq(1, 10, length = 5)     # 5 valeurs équidistantes de 1 à 10
rep(1:3, times = 3)        # répéter (1,2,3) trois fois
rep(1:3, times = c(3, 2, 4)) # répéter 1 trois fois, 2 deux fois, et 3 quatre fois
 [1]  1  2  3  4  5  6  7  8  9 10
 [1]  1  2  3  4  5  6  7  8  9 10
[1]  1.00  3.25  5.50  7.75 10.00
[1]  1.00  3.25  5.50  7.75 10.00
[1] 1 2 3 1 2 3 1 2 3
[1] 1 1 1 2 2 3 3 3 3

Réarranger les éléments d’un vecteur

taille <- c(167, 192, 173, 174, 172, 167, 171, 185, 163, 170)
rev(taille)              # inverser les éléments du vecteur
sort(taille)             # ranger par ordre croissant
sort(taille, dec = TRUE) # ranger par ordre décroissant
order(taille)            # indices pour ranger le vecteur par ordre croissant
 [1] 170 163 185 171 167 172 174 173 192 167
 [1] 163 167 167 170 171 172 173 174 185 192
 [1] 192 185 174 173 172 171 170 167 167 163
 [1]  9  1  6 10  7  5  3  4  8  2

Sommaires et statistiques descriptives

taille <- c(167, 192, 173, 174, 172, 167, 171, 185, 163, 170)
sum(taille)       # somme des éléments
prod(taille)      # produit des éléments
mean(taille)      # moyenne (empirique)
max(taille)       # maximum
min(taille)       # minimum
range(taille)     # min et max
median(taille)    # médiane (empirique)
[1] 1734
[1] 2.43e+22
[1] 173
[1] 192
[1] 163
[1] 163 192
[1] 172

Toutes ces fonctions (et d’autres encore) acceptent l’argument na.rm qui permet d’ignorer les valeurs manquantes dans le calcul. Pour voir comment cela marche, considérant l’exemple suivant.

tailes <- c(167, NA, 173, 174, 172, 167, 171, 185, 163, 170)
sum(tailes)
sum(tailes, na.rm = TRUE)
[1] NA
[1] 1542

Parmi les fonctions statistiques les plus utiles, on trouve (1) la fonction générique summary() qui résume les données sous forme de six chiffres clés (minimum, maximum, moyenne et quartiles), (2) la fonction table() qui permet de compter le nombre d’occurrences de chaque élément (unique) d’un vecteur donné.

summary(taille)                            # statistiques descriptives
table(c("A", "B", "E", "E", "A", "A", "A", "B"))  # comptage
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    163     168     172     173     174     192 

A B E 
4 2 2 

Recherche d’éléments dans un vecteur

# Positions des TRUE dans un vecteur logique
which(taille >= 180)
# Appartenance d'une ou plusieurs valeurs à un vecteur
1:10 %in% c(1, 3, 5, 9)
# Extraire les éléments uniques d'un vecteur
unique(c(5, 2, 1, 4, 6, 9, 8, 5, 7, 9))
[1] 2 8
 [1]  TRUE FALSE  TRUE FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE
[1] 5 2 1 4 6 9 8 7

Arrondi

x <- c(-3.6800000, -0.6666667, 3.1415927, 0.3333333, 1.2221201, 3.255166)
# Arrondi à un nombre défini de décimales (par défaut 0)
round(x, 4)
# Plus grand entier inférieur ou égal à l'argument
floor(x)
# Plus petit entier supérieur ou égal à l'argument
ceiling(x)
[1] -3.6800 -0.6667  3.1416  0.3333  1.2221  3.2552
[1] -4 -1  3  0  1  3
[1] -3  0  4  1  2  4

Concaténer des chaines de caractères

La fonction paste() est utile dans une situation où on souhaite « coller » des chaînes de caractères ensemble. Voici un exmple.

a <- "coucou"
b <- "comment vas-tu?"
c <- "j'espère que tout va bien."
paste(a, b, c)
[1] "coucou comment vas-tu? j'espère que tout va bien."
paste(a, b, c, sep = ", ")
[1] "coucou, comment vas-tu?, j'espère que tout va bien."
paste(a, 1:5, sep = "")
[1] "coucou1" "coucou2" "coucou3" "coucou4" "coucou5"