Chapitre 4 Structures et types de données

Il existe plusieurs types de données dans R, et différentes façons de les manipuler en découle. Le type de structure ou d’objet utilisé dépendra principalement de la nature de l’information à y stocker et des manipulations que l’on veut effectuer dessus. Trois principaux types de données et quatre principales structures sont utilisées régulièrement dans R.

4.1 Les types de données

Les principaux types de données sont:

  • les charactères c("character","another one")
  • les doubles c(1.5,2.248,3.01)
  • les entiers c(1,2,3)
  • les booléens c(TRUE,FALSE)
    Il existe aussi d’autres types, dérivés ou non des types précédents comme les dates as.POSIXct(c("1990-01-01","2017-06-03")), les complexes, ou les “raw” (séquences de bits), qui ne seront pas discutés tout de suite.
    Il est à noter qu’un manque de donnée se note généralement NA (= not applicable: non applicable) ou bien NULL par exemple pour un vecteur ou une liste de longueur nulle (i.e. vide). Il existe un type de NA pour chaque type de données : NA_character_, NA_real_, NA_integer_ et NA_complex_, mais l’utilisateur n’a généralement pas en soucier, car R applique automatiquement le type de NA associé au type de donnée.

4.1.1 Les charactères (character)

Les charactères (character) peuvent prendre n’importe quelle forme (même celle d’un chiffre), et comporter n’importe quel charactère, même un espace. Pour créer un charactère, il suffit de le déclarer entre guillemets " (ou ') comme ceci: "character". Ils peuvent être composés d’un seul charactère "a", de plusieurs "abc", ou même d’une phrase "ceci est un seul charactère". Pour créer un vecteur de plusieurs charactères, il faut utiliser la fonction c() comme nous l’avons déjà vu: c("a","b","c"). Voici un exemple incluant une déclaration et un test :

a= "a"       # a est un charactère
a
## [1] "a"
is.character(a)  # on teste si a est un charactère (retourne TRUE si la condition est vraie)
## [1] TRUE

4.1.2 Les doubles (double)

Les doubles sont des nombres décimaux. Ils sont le type de données que vous utiliserez probablement le plus souvent. Pour les déclarer, rien de plus simple, il suffit d’écrire votre chiffre, puis de l’utiliser comme bon vous semble. Voici un petit exemple :

a= 1.56       # a est un double
a*83.550      # il peut être multiplié par un autre double
## [1] 130.338
is.double(a)  # on teste si a est un double (équivalent de is.numeric())
## [1] TRUE

Les doubles ont en plus d’autres valeurs possibles qui correspondent plutôt à des erreurs de calculs ou de précision:

  • le NaN, qui signifie Not a Number (= Pas un nombre). Qui est souvent le résultat d’une opération mathématique interdite, comme un logarithme ou une racine carrée d’un nombre négatif.
  • le -Inf et le Inf, qui sont le résultat d’une opération mathématique qui ne peut pas être calculée car trop grande ou trop petite. Exemple :
log(-1)
## [1] NaN
10^89999
## [1] Inf
-10^89999
## [1] -Inf

Pour bien comprendre ce type d’erreurs, et comment ils sont utilisés par R, vous devez d’abord comprendre comment un ordinateur perçoit les doubles. Je comprends que ce type d’information puisse moins vous intéresser, mais je pense fermement que vous devez connaître ceci avant de passer à la suite. Cependant, vous pouvez sauter le paragraphe qui suit pour une première lecture, et aller directement à Les entiers (integer).

Cette partie peut vous paraître difficile et éloignée du sujet de prime abord, mais vous verrez par la suite à quel point elle peut être importante lors de certains calculs.
Si vous lisez ce livre depuis un navigateur avec une connexion internet, je vous renvoie à l’article wikipédia sur le sujet en français ou celui en anglais encore plus complet, sinon, je vais vous faire ici un petit résumé simplifié.

En informatique, un double est un type de donnée utilisé pour représenter les nombres décimaux (nombre à virgule). Comme un ordinateur utilise des suites de bits (0 ou 1) pour fonctionner, il doit représenter les nombres décimaux avec une précision donnée, c’est à dire un nombre de bits donné pour représenter un nombre. Nous les humains faisons de même. En effet, pour écrire en décimale le nombre pi, nous n’écrirons certainement pas tous les chiffres après la virgule (je vous met au défi), mais nous en feront plutôt une approximation. Parfois nous écrirons 3.14 pour aller très vite, parfois lorsque la précision s’impose nous écrirons 3.141593 (ou plus). Comme un ordinateur ne peut pas savoir à l’avance avec quelle précision nous voulons travailler, nous lui imposons une précision fixe, qui aujourd’hui est le format double précision (d’où le nom de double) 64 bits de la norme (IEEE 754). Ces nombres sont représentés grâce à trois informations: le signe du nombre s (- ou +), la mantisse m (~les chiffres du nombre) et un exposant e (entier relatif qui donne la position de la virgule dans la mantisse, ce qui donne le nom de virgule flottante). Il s’agit un peu d’un équivalent de la notation scientifique. Un nombre peut donc être représenté comme ceci3 :

En double précision, ces trois informations ensemble ne doivent pas dépasser 64 bits. L’encodage est donc divisé comme suit: 1 bit pour le signe, 11 bits pour l’exposant et 52 bits pour la mantisse, ce qui donne 53 bits de précision, donc environ 16 chiffres significatifs. Si vous avez bien compris comment les doubles sont encodés, alors vous aurez compris que R peut donc représenter des nombres avec beaucoup de précision, mais pas avec une précision infinie.
Que vous ayez bien compris ou non, retenez ces deux conclusion:

1- La précision n’est pas infinie:
Il est important de toujours garder en tête que la précision des calculs dans R n’est pas infinie, et donc que sous certaines conditions R peut présenter un comportement non valide mathématiquement, comme par exemple lors d’une soustraction de nombres extrêmement proches de zéro comme suit :

10^-325-10^-324
## [1] 0

Comme vous pouvez le voir R retourne 0, ce qui est faux. Un calcul de cette précision peut paraître superflu mais ce genre d’erreur peut s’accumuler de calculs en calculs et devenir bien plus grande par la suite.
Bien sûr, il est très rare d’utiliser de telles précisions, et les erreurs engendrées n’auront aucun impact réel sur vos calculs. Pour l’exemple, voici un autre calcul très précis, que R peut gérer (si votre ordinateur le permet) :

10^-324-10^-323
## [1] -9.881313e-324

NB: pour voir quel degré de précision votre ordinateur (et R) peut gérer, vous pouvez regarder le contenu de l’objet .Machine dans la console de R.

2- La précision en informatique = chiffres significatifs
Il faut retenir que les grands nombres ont moins de chiffres après la virgule. En effet, la précision en informatique se réfère aux chiffres significatifs, c’est à dire au nombre de chiffres que comporte un nombre au total (avant ou après la virgule). Ceci est différent de la “précision décimale”, qui se réfère au nombre de chiffres après la virgule.
Comme la précision ne change pas avec le nombre considéré, plus un nombre est grand (positif ou négatif), moins on peut représenter de chiffres après sa virgule. En effet, 0.003 comporte 4 chiffres, dont 3 après la virgule. 3000 comporte 4 chiffres aussi, mais aucun après la virgule. Ils ont la même précision arithmétique au sens de chiffres significatifs (4), mais pas au sens de “précision décimale” qui donnerait 3000.0000 pour une précision de 4.
Regardez par vous même, on voit que R est capable de calculer ceci :

a= 10^-324-10^-323
# On teste si "a" est différent de 0:
a!=0
## [1] TRUE

(a est bien différent de 0)

Mais il ne pourra pas calculer ceci :

a= 1-10^-323
# On teste si "a" est différent de 1:
a!=1
## [1] FALSE

(a est considéré égal à 1, donc la soustraction 1-10^-323 n’est même pas prise en compte)

On peu aussi noter que même si R arrive à utiliser des nombres avec de grandes précisions, celui-ci arrondi souvent le résultat lorsqu’il l’affiche dans la console. Pour voir un nombre complet, on peut utliser la fonction print() avec son argument digits, qui donne le nombre de décimale voulues, comme ceci:

print(1+ 2.2e-14,digits = 22)
## [1] 1.000000000000022

Enfin, si la précision vous importe vraiment et que vous devez utiliser des chiffres plus précis que la double précision, vous pouvez jeter un oeil au package Rmpfr et le package Brobdingnag.

4.1.3 Les entiers (integer)

En informatique, les entiers sont des entiers relatifs (nombre avec signe). Pour être différenciés des doubles, les entiers (integer) sont déclarés suivis de la lettre L comme suit :

a= 1L
b= 24L
c= -500L
paste(a,b,c)
## [1] "1 24 -500"
is.integer(a) # teste si a est un entier
## [1] TRUE

4.1.4 Les booléens (boolean or logical)

Les booléens sont des nombres logiques, aussi appelés variable d’état. Les booléens ont deux valeurs possibles uniquement, TRUE (vrai) et FALSE (faux).
Dans R T est un raccourci pour TRUE, et F un raccourci pour FALSE. Voici comment déclarer et tester un booléen :

a= TRUE
b= T          # équivalent de a
c= FALSE
d= F          # équivalent de c
is.logical(a) # teste si a est un booléen
## [1] TRUE

4.1.5 En bonus, les facteurs (factors)

Les facteurs sont un type de données un peu spéciaux. Ils permettent d’utiliser des catégories de données dans une même variable. On peut prendre l’exemple d’une personne qui regarde de quelle couleur sont les voitures qui passent devant son entrée, s’il relève 3 voitures rouges, deux bleues et quatre blanches, alors on peut dire que nous avons trois catégories de couleurs de voitures: rouge, bleue, blanche. Pour déclarer ceci dans R, nous ferions comme suit :

couleurs= factor(c("rouge","rouge","rouge","bleue","bleue","blanche",
                   "blanche","blanche","blanche"))
couleurs          # nous avons un vecteur de charactères, et R reconnait automatiquement les 3 catégories (levels) 
## [1] rouge   rouge   rouge   bleue   bleue   blanche blanche blanche blanche
## Levels: blanche bleue rouge

On voit que couleurs se présente comme un vecteur, mais contient un métadonnée de plus, les levels, qui résument les valeurs uniques du vecteur, et donc qui décrivent les différentes valeurs possible du vecteur.

La fonction level permet de retrouver les catégories :

levels(couleurs)
## [1] "blanche" "bleue"   "rouge"

Les facteurs sont souvent utilisés dans d’autres fonctions comme pour les graphiques ou les modèles. En général, il est préférable d’éviter leur utilisation et de les remplacer par un autre type de donnée, à moins d’en avoir un réel besoin.

4.2 Les transformations

R est un language extrèmement maléable, si bien qu’il existe des “ponts” entre les types de données. On pourra donc très facilement transformer un type de données en un autre dans certains cas.

  1. integer vers double :
    il s’agit de la transformation la plus facile. R ne requiert aucun préalable à cette transformation, si bien que celle-ci se fait sans même y réfléchir:
a= 1L           # a est déclaré comme un entier égal à 1
is.integer(a)   # a est bien considéré comme un entier
## [1] TRUE
b= a*2.5        # on multiplie a par un double et on le stocke dans b
is(b)           # b est lui-même un double
## [1] "numeric" "vector"
  1. double to integer :
    L’inverse n’est pas aussi simple et doit se faire en utilisant une fonction de R semblable à la fonction de test (is.integer) que nous avons déjà vu : as.integer. En voici un exemple :
a= c(2,2.5,3.8)   # a est déclaré comme un double
is.double(a)      # a est bien considéré comme un double
## [1] TRUE
b= as.integer(a)  # on force a à devenir un entier
b                 # b est maintenant un integer (R à tronqué le chiffre)
## [1] 2 2 3
  1. double (ou integer) to character :
    Cette transformation est aussi assez simple et peut se faire en utilisant la fonction as.character :
a= c(2,2.5,3.8)     # a est déclaré comme un double
is.double(a)        # a est bien considéré comme un double
## [1] TRUE
b= as.character(a)  # on force a à devenir un character
b                   
## [1] "2"   "2.5" "3.8"

b est maintenant un charactère (notez les guillemets qui entourent chaque chiffre)

  1. character to double (ou integer) :
    Comme vous l’avez deviné, cette transformation peut se faire grâce à la fonction as.double. Cependant, il faut être très prudent lorsque l’on fait une transformation dans ce sens, car R peut parfois présenter des comportements inattendus.
a= c("1","2","3")   # a est déclaré comme un vecteur de 3 charactères
is.character(a)     # a est bien considéré comme un charactère
## [1] TRUE
b= as.double(a)     # on force a à devenir un double
b                   # b est une version de a en double
## [1] 1 2 3

Maintenant un exemple avec des facteurs, qui peuvent donner des résultats inattendus lorsqu’ils sont composés de charactères comportant des chiffres et des lettres :

a= factor(c("1","a","3"))   # a est déclaré comme un facteur de logueur 3
b= as.numeric(a)            # on force a à devenir un double
b                           # b est bien un double, mais le résultat est quelque peu déroutant
## [1] 1 3 2
is(b)
## [1] "numeric" "vector"

Comme on peut le voir, la transformation est déroutante : le “3” du facteur est devenu un 2, et le “a” un 3. Pour comprendre ce qu’il s’est passé, il faut savoir que pour transformer un facteur en numérique, R prends les catégories comme des charactères, puis les trie alphanumériquement (i.e. de 0 à 9 puis de A à Z), puis alloue l’index de chaque catégorie comme nouvelle valeur. Donc ici R à décidé de l’ordre suivant dans les catégories : “1”<“3”<“a”, puis leur à alloué un index : “1”=1, “3”=2, “a”=3, et a remplacé les valeurs de chaque catégorie par son index pour que “1”,“a”,“3” devienne 1,3,2. Ce type d’erreur peut être évité en utilisant la combinaison de fonctions suivantes :

a= factor(c("1","a","3"))   # a est déclaré comme un facteur de longueur 3
b= as.numeric(levels(a))[a] # on force a à devenir un double
## Warning: NAs introduits lors de la conversion automatique
b                           
## [1]  1 NA  3

b est bien un double, le résultat est bon, et le charactère “a” est transformé en NA.

Maintenant que vous connaissez mieux les charactères, les doubles, les entiers, et les booléens, vous allez voir comment les organiser dans des structures de données qui vous permettront de les stocker dans des objets plus ou moins complexes.

4.3 Les Structures de données

R met à disposition de ses utilisateurs quatre grands types de structures de données plus ou moins liées: les vecteurs, les matrices, les tableaux et les listes.

4.3.1 Vecteurs

Nous avons déjà vu un premier exemple de vecteurs dans le chapitre précédent (Premiers pas), qui introduisait la fabrication d’un vecteur contenant des chiffres. Les vecteurs sont une structure de données à une dimension, c’est à dire qu’il s’agit d’une suite de données rangées en “ligne”. Un vecteur ne peut contenir qu’un seul type de données à la fois (charactère, booléen…). Si l’on construit un vecteur avec plusieurs types de données consécutifs, ils sont alors transformés de la même façon que nous avons vu les tranformations précédement dans Les transformations. Il est à retenir que R essaye toujours de prendre le types de donnée qui gardera le plus d’information. Par exemple un mélange de charactères et de doubles sera transformé en charactère pour ne pas perdre l’information des charactères (qui seraient transformés en NA autrement).
Il existe plusieurs moyens de créer un vecteur. Tous ont un avantage associé, et seront utilisés en fonction du contexte:

  • En utilisant as.vector pour créer un vecteur de la taille désirée, que l’on remplira par la suite. Comme les vecteurs ne peuvent contenir qu’un seul type de données, il faut déclarer le type dès la création grâce à l’argument “mode”. Les différents modes sont logical (= booléen), integer (= entier), numeric (= double), complex (= complexe), character (= charactère) and raw (= bits). Voici un exemple de vecteur numérique:
a= vector(mode = "numeric", length = 10)   # a est un vecteur de longueur 10
a
##  [1] 0 0 0 0 0 0 0 0 0 0
  • En utilisant la fonction c(), qui concatène ses arguments :
a= c(1,10,8)
a
## [1]  1 10  8
  • En utilisant d’autres fonction comme seq(), rep(), : etc… :
a= seq(from = 1, to = 10, by = 1)
a= rep(x = 0, times= 10)
a= rnorm(n = 10, mean = 1, sd = 2)

4.3.2 Matrices

Une matrice est très semblable à un vecteur, sauf qu’elle comporte deux dimensions, il s’agit là d’une matrice dans son sens mathématique. Comme les vecteurs, les matrices ne peuvent contenir qu’un seul type de données. Voici un exemple de création de matrice:

matrix(data = 1:9, nrow = 3)   # une matrice
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9

La fonction matrix est très utile car on peut choisir le nombre de lignes et/ou de colonnes, ainsi que le sens de remplissage des données avec l’argument by.row. La fonction matrix est un très bon utilitaire pour construire des structures 2D vides notemment, comme suit:

matrix(data = NA, nrow = 8, ncol=2)   # une matrice 8*2 comportant la valeur NA
##      [,1] [,2]
## [1,]   NA   NA
## [2,]   NA   NA
## [3,]   NA   NA
## [4,]   NA   NA
## [5,]   NA   NA
## [6,]   NA   NA
## [7,]   NA   NA
## [8,]   NA   NA

Une matrice peut aussi comporter une seule colonne, ou une seule ligne.

4.3.3 Tableaux

Il existe deux types de tableaux dans R: array et data.frame.
Le premier est rarement utilisé. Il s’agit ni plus ni moins d’un vecteur à n dimensions (englobe donc vecteur et matrices).

array(data = 1:9, dim = 9)   # un array tel un vecteur
## [1] 1 2 3 4 5 6 7 8 9
array(data = 1:9, dim = c(3,3))   # un array tel une matrice 3*3
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
array(data = 1:9, dim = c(3,3,2))   # un array tel une liste de 2 matrices de 3*3 (dimension 3)
## , , 1
## 
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
## 
## , , 2
## 
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9

Le second, le data.frame, est peut-être la structure la plus utilisée dans R. Cette structure représente le sens commun que l’on se fait d’un tableau. Structurellement, le data.frame se présente donc comme un tableau comportant un nombre défini de colonnes et de lignes. Chaque colonne comporte le même nombre de lignes. Dans R, un data.frame est une liste de vecteurs de même longueur. Le plus grand avantage du data.frame est que chaque colonne peut contenir un type de donnée différent.

data.frame(a= c("Jour 1", "Jour 2", "Jour 3"), b=c(40, 50, 45))   # un data.frame
##        a  b
## 1 Jour 1 40
## 2 Jour 2 50
## 3 Jour 3 45

Les data.frame sont utilisés par la grande majorité des fonctions dans R.

4.3.4 Listes

Les listes (list) sont aussi un type de structure très important dans R. Il faut penser la liste comme étant au data.frame ce qu’est l’array à la matrice. Il s’agit d’un data.frame de dimension n. On peut mettre n’importe quel type de données de n’importe quelle taille dans une liste, même une autre liste (= nested list).

list(a= c("Jour 1", "Jour 2", "Jour 3"), b=c(40, 50, 45), c= 1, d= list(1:3, 8:4, "a"))
## $a
## [1] "Jour 1" "Jour 2" "Jour 3"
## 
## $b
## [1] 40 50 45
## 
## $c
## [1] 1
## 
## $d
## $d[[1]]
## [1] 1 2 3
## 
## $d[[2]]
## [1] 8 7 6 5 4
## 
## $d[[3]]
## [1] "a"

Les listes sont un peu complexe à appréhender mais sont certainement le type de structure le plus maléable, et finalement le plus simple à travailler. Il est à noter que le data.frame est en fait une liste de vecteurs. On peut donc remplir l’une de ses colonnes par une liste, mais ce type d’utilisation est plutôt déconseillé dans un premier temps car il limite l’utilisation de fonctions spéciales adaptées aux data.frame, mais aussi à celles adaptées aux listes.

4.3.5 Attributs

Il est possible d’associer n’importe quelle métadonnée à un objet dans R. Ces métadonnées sont appelés attributs. Ces attributs n’ont aucune influence sur la valeur de la donnée elle-même, mais elle peut apporter des informations complémentaires à l’utilisateur ou à une fonction.

Voici un exemple d’attribut qui permet à l’utilisateur de se rappeler l’unité d’un objet:

a= 1   # a vaut 1 cm
attr(a, "unit")= "cm"

Certains attributs sont utilisés par des fonctions. C’est le cas du nom et de la dimension d’un objet.

Voici un exemple de la hauteur de 10 arbres dans une forêt:

hauteur= rnorm(n = 10, mean = 25)

Cette hauteur n’a pas de nom (names() retourne NULL):

names(hauteur)
## NULL

On peut assigner un nom comme suit:

names(hauteur)= paste0("arbre_",1:10)
names(hauteur)
##  [1] "arbre_1"  "arbre_2"  "arbre_3"  "arbre_4"  "arbre_5"  "arbre_6"  "arbre_7"  "arbre_8" 
##  [9] "arbre_9"  "arbre_10"

On peut aussi retrouver le nom de chaque valeur grâce à la fonction attributes():

attributes(hauteur)
## $names
##  [1] "arbre_1"  "arbre_2"  "arbre_3"  "arbre_4"  "arbre_5"  "arbre_6"  "arbre_7"  "arbre_8" 
##  [9] "arbre_9"  "arbre_10"

Idem pour la dimension d’une matrice avec dim(). On crée une matrice de dimension 2,3:

matrice= matrix(1:8, 2,3)
## Warning in matrix(1:8, 2, 3): la longueur des données [8] n'est pas un diviseur ni un
## multiple du nombre de colonnes [3]
matrice
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6

Sa dimension est 2,3:

dim(matrice)
## [1] 2 3

On peut la modifier comme ceci:

dim(matrice)= c(3,2)
matrice
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6

Ou en utilisant la fonction attr():

attr(matrice,"dim")= c(2,3)
matrice
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6

Les fonctions names() et dim() sont en fait des raccourcis pour attr(matrice,"names") et attr(matrice,"dim") respectivement.

4.4 Manipuler les structures

La manipulation des structures se fait en accord avec les spécificités de chacunes.

4.4.1 Index et Test

La manipulation la plus courante est l’indexage. En d’autres termes, il s’agit là de récupérer les valeurs d’une structure en fonction de sa position, de son nom ou d’une condition. L’index se fait le plus souvent en utilisant la fonction [, appelée fonction extract. Par exemple, pour récupérer la troisième valeur d’un vecteur, on utilisera la fonction comme suit: a[3]. Il est à noter que l’indexage se fait à partir de 1, car la première valeur du vecteur est en position 1. Cela peut porter à confusion pour les utilisateurs venant d’autres languages de programmation tels que Python, qui indexe à partir de 0. Une autre particularité de R est l’utilisation du - comme un sauf. Donc a[-3] récupèrera le vecteur a sauf sa troisième valeur. Lorsque l’on a plus d’une dimension (e.g. matrice ou data.frame), on sépare l’index de chaque dimension par une virgule (e.g. [ligne,colonne]). Pour récupérer les objets d’une liste, on utilisera la fonction [[. On peut aussi indexer un vecteur par le nom de son objet comme suit a["nom de l'objet"] mais aussi en testant une condition comme ceci a[c(T,T,F)]. Une deuxième fonction que l’on peut utiliser pour le data.frame et la list est la fonction $. Celle-ci indexe les colonnes du premier et les objets du second par leur nom.

  • Vecteur
a= c(10:15) # a est un vecteur numérique de 10 à 20.
a[3]        # on veut récupérer la troisième valeur du vecteur a
## [1] 12
a[c(1,5,3)] # on veut récupérer la 1e, la 5e et la 3e valeur de a
## [1] 10 14 12
a[-1]       # on veut récupérer toutes les valeurs de a sauf la première.
## [1] 11 12 13 14 15
a[c(T,F,F,T,T)] # on veut récupérer toutes les valeurs de a sauf la 2e et 3e valeur qui sont refusées par le FALSE (F).
## [1] 10 13 14 15
  • matrice:
a= matrix(10:21, nrow= 3) # a est une matrice
a[3,]                     # on veut récupérer la troisième ligne entière
## [1] 12 15 18 21
a[c(1,3), 1]              # on veut récupérer la 1e et la 3e ligne, mais seulement la 1e colonne
## [1] 10 12
a[-1,-2]                  # on veut récupérer toutes les lignes sauf la 1e et toutes les colonnes sauf la 2e
##      [,1] [,2] [,3]
## [1,]   11   17   20
## [2,]   12   18   21
  • data.frame
a= data.frame(Num= c(1:10), Prix= c(11:20)) # a est un data.frame
a[3,]         # comme sur les matrices, on veut récupérer la troisième ligne entière
##   Num Prix
## 3   3   13
a[c(1,3), 1]  # on veut récupérer la 1e et la 3e ligne, mais seulement la 1e colonne
## [1] 1 3
a[-1,-2]      # on veut récupérer toutes les lignes sauf la 1e et toutes les colonnes sauf la 2e
## [1]  2  3  4  5  6  7  8  9 10
a$Prix        # on veut récupérer la deuxième colonne par son nom avec la fonction `$`.
##  [1] 11 12 13 14 15 16 17 18 19 20
a["Num"]      # on veut récupérer la 1e colonne par son nom avec la fonction `[`
##    Num
## 1    1
## 2    2
## 3    3
## 4    4
## 5    5
## 6    6
## 7    7
## 8    8
## 9    9
## 10  10
  • liste
a= list(Num= c(1:3), Prix= c(11:13), Id_et_serie= list(Id= c(1,1,1), serie= c(2,2,2)), Classe= data.frame(a=1:3,b=1:3)) # a est un data.frame
a[1:2]        # on veut récupérer une liste des 1er et 2nd objets de la liste
## $Num
## [1] 1 2 3
## 
## $Prix
## [1] 11 12 13
a[[1]]        # on veut récupérer les valeurs du 1er objet de la liste
## [1] 1 2 3
a[-1]         # on veut récupérer une liste de tous les objets de la liste sauf le 1er
## $Prix
## [1] 11 12 13
## 
## $Id_et_serie
## $Id_et_serie$Id
## [1] 1 1 1
## 
## $Id_et_serie$serie
## [1] 2 2 2
## 
## 
## $Classe
##   a b
## 1 1 1
## 2 2 2
## 3 3 3
a[[3]][1]     # on veut récupérer les valeurs du premier objet de la liste en 3e position de la liste a.
## $Id
## [1] 1 1 1
a[[4]][,1]    # on veut récupérer les valeurs de la 1e colonne du data.frame en 4e position de la liste a.
## [1] 1 2 3
a$Classe[,1]  # on mélange l'utilisation des deux fonctions `$` et `[` pour faire de même
## [1] 1 2 3
a$Prix        # on veut récupérer les valeurs de l'objet nommé Prix
## [1] 11 12 13
a$Id_et_serie$serie # on veut récupérer les valeurs de l'objet nommé serie dans l'objet nommé Id_et_serie
## [1] 2 2 2
a[c("Num","Classe")]# on veut récupérer le 1er et 4e objets de la liste a
## $Num
## [1] 1 2 3
## 
## $Classe
##   a b
## 1 1 1
## 2 2 2
## 3 3 3

Donc pour résumer, l’indexage commence à 1, et l’index se fait comme suit: vecteurs [i], matrices/tableaux [i,j] et listes [[i,j]] ou [1] ou [[1]] Pour indexer plusieurs éléments:

  • selon numéro de l’index lignes/colonnes [1:10], [,1:10]
  • selon condition test [c(T,T,F,T)]

4.4.2 Remplacer, assigner

Il est possible de remplacer des valeurs dans une structure en spécifiant l’index de la valeur à remplacer et lui ré-assignant une nouvelle valeur :

a= c(10:15) # a est un vecteur numérique de 10 à 20.
a[3]        # la troisième valeur de a est de 12
## [1] 12

On remplace sa valeur par 5:

a[3]= 5     
a           # La 3e valeur est modifiée à 5
## [1] 10 11  5 13 14 15

Attention, si on remplace une valeur par un autre type de données, cela peut changer le type de tout le vecteur:

a[1]= "a"   
a           # a a été modifié en charactere
## [1] "a"  "11" "5"  "13" "14" "15"

On peut aussi modifier plusieurs valeurs à la fois:

a[1:3]= 5
a
## [1] "5"  "5"  "5"  "13" "14" "15"

4.4.3 Concaténation

On peut aussi concaténer les différentes structures de données:

  • vecteur, en utilisant la fonction c() :
a= 1:10
b= c(2,8)
vec= c(a,b)
vec
##  [1]  1  2  3  4  5  6  7  8  9 10  2  8
  • matrice/data.frame en utilisant rbind pour concatener par lignes, cbind pour concatener par colonnes :
a= matrix(data= 1:9, nrow = 3)
b= matrix(data= 10:18, nrow = 3)
mat_c= cbind(a,b)
mat_c
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]    1    4    7   10   13   16
## [2,]    2    5    8   11   14   17
## [3,]    3    6    9   12   15   18
a= matrix(data= 1:9, nrow = 3)
b= matrix(data= 10:18, nrow = 3)
mat_r= rbind(a,b)
mat_r
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
## [4,]   10   13   16
## [5,]   11   14   17
## [6,]   12   15   18

4.4.4 Transformation

On peut transformer des structures simples très facilement dan R, comme passer d’un charactère à un numérique par exemple (voir [transform_datatype]), mais aussi pour des structures plus complexes, comme les matrices, les tableaux et les listes. Les structures ont très souvent une fonction associée pour passer de l’une vers l’autre.

Par exemple pour transformer quelque chose en matrice, on utilisera as.matrix, as.data.frame pour les tableaux, as.vector pour les vecteurs, ou encore as.list pour les listes. Bien sûr l’utilisateur doit s’efforcer de présenter les données de façons structurées pour que ces fonctions puissent effectuer la transformation.

Une liste pourra par exemple être tranformée en data.frame seulement si son contenu est de même longueur:

liste= list(a= 1:2, b= 3:4)
as.data.frame(liste)
##   a b
## 1 1 3
## 2 2 4

Ici le data.frame est bien crée car a et b dans liste ont la même longueur. Par contre si b était plus long, la fonction as.data.frame ne sait pas a priori ce qu’elle doit faire, donc elle retourne une erreur.

4.4.5 Transposition

Une matrice peut être transposée grâce à la fonction t() comme suit:

matrice= matrix(1:9, nrow = 3)
t(matrice)
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9

On peut aussi transposer un data.frame avec t(), mais celui-ci est alors transformé en matrice:

df= as.data.frame(matrice)
t(df)
##    [,1] [,2] [,3]
## V1    1    2    3
## V2    4    5    6
## V3    7    8    9

La transformation en matrice peut être un problème si l’on utilise des colonnes de types différent, car la fonction va uniformiser le type des données:

df= data.frame(a= 1:2, b= c("1","2"))
t(df)
##   [,1] [,2]
## a "1"  "2" 
## b "1"  "2"

Ici toutes les données sont transformées en charactère.

4.4.6 Opérations

Il est très simple d’appliquer des opérations mathématiques sur des structures dans R car ces fonctions sont vectorisées, c’est à dire que les fonctions +, -, *, /,… peuvent s’appliquer à plusieurs valeurs d’un seul coup. Par exemple on peut multiplier un vecteur par un autre comme ceci:

a= c(1:5)
b= c(6:10)
a * b
## [1]  6 14 24 36 50

On peut aussi multiplier des colonnes de data.frame:

df= data.frame(a= c(1:5), b= c(6:10))
df$a * df$b
## [1]  6 14 24 36 50

Pour plus de détails, voir le chapitre “[datascience1]”.