Dernière mise à jour: 2021-02-23 21:22.
Dans ce fichier on va apprendre à extraire et manipuler des parties des structures de données dans R.
Pour télécharger et ouvrir ce fichier, vérifiez d’abord d’être dans le bon dossier de travail, puis copier-coller ces lignes dans l’invite de commande R:
download.file("http://homepages.ulb.ac.be/~mgagliol/INFOD203/indexation.r",
"indexation.r")
file.edit("indexation.r")
Pour le cours INFOD203: Une partie de la matière dans ce fichier est rendue obsolète par le tidyverse. Ceci dit, ça reste correcte, et peut être utile pour une meilleure connaissance du langage R. Plus précisement les sections optionnelles sont: 2.1.3, 2.2, 2.3, 2.4, 2.5.2.
Pour le cours SOCAD460: tout le fichier reste pertinent.
L’indexation permets de lire/écrire une partie des valeurs faisant partie d’un vecteur, un data.frame, ou d’autres structures «indexables» (list, matrix, array, …)
Si x est un objet indexable et i est un index:
x: x[i]x: x[i] <- yVoire aussi ancienne version du syllabus, sec. 5.2-3, pages 54-65.
"logical")Des exemples de vecteurs qu’on va utiliser dans la suite
mots <- c("un", "deux", "trois", "quatre", "cinq")
mots
[1] "un" "deux" "trois" "quatre" "cinq"
nombres <- 1:5
nombres
[1] 1 2 3 4 5
dizaines <- seq(from = 10, to = 50, by = 10) # séquence de 10 à 50, avec un pas de 10
dizaines
[1] 10 20 30 40 50
"integer")Soit x un vecteur de longueur n == length(x) Tout vecteur i de nombres entiers entre 1 et n (inclus) peut être utilisé pour indexer x ainsi: x[i], le résultat x[i] étant un vecteur de la même longueur que i obtenu en concaténant les éléments de x correspondants aux positions indiqués dans i
mots
[1] "un" "deux" "trois" "quatre" "cinq"
mots[2] # rappel: 2 est un vecteur de longueur 1
[1] "deux"
2:4 # 2:4 est c(2, 3, 4), vecteur de longueur 3
[1] 2 3 4
mots[2:4]
[1] "deux" "trois" "quatre"
c(1:3, 5) #la combinaison de deux vecteurs est un vecteur
[1] 1 2 3 5
mots[c(1:3, 5)]
[1] "un" "deux" "trois" "cinq"
c(1:2, c(4, 5)) #la combinaison de deux vecteurs est un vecteur
[1] 1 2 4 5
mots[c(1:2, c(4, 5))]
[1] "un" "deux" "quatre" "cinq"
dizaines
[1] 10 20 30 40 50
dizaines[2]
[1] 20
dizaines[2:4]
[1] 20 30 40
Si on ne connaît pas la longueur à l’avance, on peut utiliser length ainsi:
length(mots)
[1] 5
3:length(mots)
[1] 3 4 5
mots[3:length(mots)]
[1] "trois" "quatre" "cinq"
dizaines[4:length(dizaines)]
[1] 40 50
on peut utiliser une indexation directe pour répéter des éléments ou en changer l’ordre
mots[c(5, 4, 3, 2, 1)]
[1] "cinq" "quatre" "trois" "deux" "un"
nombres[c(4, 4, 4)]
[1] 4 4 4
dizaines[c(1, 2, 1, 5, 2, 2, 3)]
[1] 10 20 10 50 20 20 30
Au lieu des valeurs explicites on peut utiliser une variable comme index
index <- c(2, 1, 3, 2)
index
[1] 2 1 3 2
dizaines[index]
[1] 20 10 30 20
mots[index]
[1] "deux" "un" "trois" "deux"
Avec l’indexation directe, la longueur du résultat est toujours égale à la longueur de l’index:
length(x[i]) == length(i)
Attention a ne pas utiliser d’index == 0, ni d’index > n. Dans les deux cas, R nous ne donne pas un message d’erreur, mais le résultat risque d’introduire des erreurs par la suite, difficiles à dépister:
dizaines[0] # pas de message d'erreur, résultat vide
numeric(0)
dizaines[6] # pas de message d'erreur, résultat `== NA`
[1] NA
NA (Not Available) est une valeur spéciale utilisé par par R pour désigner les valeurs manquantes (par exemple, une réponse refusée par un des sujets dans les résultats d’un questionnaire).
"logical")L’indexation la plus utilisé, nous permettant de sélectionner des éléments pas sur base de leur position, mais par une condition logique sur leur valeur. Par exemple:
dizaines
[1] 10 20 30 40 50
dizaines[dizaines <= 32] # valeurs inférieurs ou égales à `32`
[1] 10 20 30
dizaines[dizaines < 23 | dizaines > 39] # valeurs inférieurs à 23 ou supérieurs à 39
[1] 10 20 40 50
Comment ça marche ? C’est possible car:
dizaines <= 32
[1] TRUE TRUE TRUE FALSE FALSE
dizaines[dizaines <= 32]
[1] 10 20 30
dizaines < 23
[1] TRUE TRUE FALSE FALSE FALSE
dizaines > 39
[1] FALSE FALSE FALSE TRUE TRUE
dizaines < 23 | dizaines > 39
[1] TRUE TRUE FALSE TRUE TRUE
dizaines[dizaines < 23 | dizaines > 39]
[1] 10 20 40 50
Voyons cela plus en le détail. Soit x un vecteur de longueur n == length(x). Tout vecteur i de valeurs booléens (class "logical") de longueur n peut être utilisé pour indexer x ainsi: x[i], le résultat étant un vecteur d’une longueur égale au nombre de TRUE dans i, obtenu en sélectionnant les éléments de x correspondants aux valeurs TRUE dans i:
mots
[1] "un" "deux" "trois" "quatre" "cinq"
mots[c(FALSE, TRUE, FALSE, FALSE, FALSE)]
[1] "deux"
mots[c(FALSE, TRUE, TRUE, TRUE, FALSE)]
[1] "deux" "trois" "quatre"
mots[c(FALSE, FALSE, TRUE, FALSE, TRUE)]
[1] "trois" "cinq"
dizaines
[1] 10 20 30 40 50
dizaines[c(FALSE, TRUE, FALSE, FALSE, FALSE)]
[1] 20
dizaines[c(FALSE, TRUE, TRUE, TRUE, FALSE)]
[1] 20 30 40
dizaines[c(FALSE, FALSE, TRUE, FALSE, TRUE)]
[1] 30 50
Même chose indirectement, avec une variable:
index <- c(TRUE, FALSE, FALSE, FALSE, TRUE)
index
[1] TRUE FALSE FALSE FALSE TRUE
dizaines[index]
[1] 10 50
mots[index]
[1] "un" "cinq"
L’intérêt de cette indexation est d’utiliser le résultat d’un opérateur booléen appliqué au vecteur comme index pour le vecteur même (voir slides sur la logique ou Syllabus p. 57-8).
Par exemple:
dizaines >= 20 # le résultat est un vecteur booléen de la même taille que dizaines
[1] FALSE TRUE TRUE TRUE TRUE
dizaines[dizaines >= 20] # je peux donc l'utiliser pour indexer dizaines
[1] 20 30 40 50
Même chose indirectement, avec une variable:
index <- (dizaines >= 20)
index
[1] FALSE TRUE TRUE TRUE TRUE
dizaines[index]
[1] 20 30 40 50
Je peux utiliser des opérateurs pour combiner différents conditions. Dizaines entre 20 et 40:
dizaines[dizaines >= 20 & dizaines <= 40]
[1] 20 30 40
Dizaines inférieurs à 20 ou supérieurs à 40
dizaines[dizaines < 20 | dizaines > 40]
[1] 10 50
Dizaines à la fois inférieur à 20 et supérieurs à 40:
dizaines[dizaines < 20 & dizaines > 40]
numeric(0)
il y en n’a pas… le résultat est un vecteur «vide»: numeric(0) qui signifie: vecteur de classe "numeric" et longueur 0. Remarque: l’indexation par booléen peut seulement rendre un sous-ensemble des valeurs dans le vecteur indexé, sans changements d’ordre ni répétitions. Tandis que l’indexation directe nous permet de combiner les éléments du vecteur comment on veux, en changeant leur ordre, ou les répétant.
Par exemple, on ne peut pas reproduire les indexations suivantes avec des booléens:
dizaines[c(2, 2, 2, 2, 2, 2, 2, 2, 2)]
[1] 20 20 20 20 20 20 20 20 20
mots[c(3, 2, 1)]
[1] "trois" "deux" "un"
nombres[c(2, 1, 3, 2, 4, 5, 2)]
[1] 2 1 3 2 4 5 2
Remarque: dans l’indexation par entiers, length(x[i]) == length(i). Dans l’indexation par booléens, on doit avoir length(i) == length(x), sinon on fait du recyclage!
Tout comme pour les opérateurs (voir initiation), pour l’assignation aussi il faut faire gaffe au recyclage.
Indépendamment du type d’indexation utilisé, pour éditer les valeurs indexées on peut faire suivre l’indexation par une assignation: par ex x[i] <- val assigne la/les valeur(s) en val aux éléments de x indexés par i.
Quand on fait une assignation après indexation ( x[i] <- v ) on a trois possibilités:
length(x[i]) == length(v) ) Dans ce cas, les valeurs en v sont copiés un à un en x[i], en gardant leur ordre Exemples:dizaines
[1] 10 20 30 40 50
dizaines[4] <- 44
dizaines
[1] 10 20 30 44 50
dizaines[c(2, 5)] <- c(22, 55)
dizaines
[1] 10 22 30 44 55
<- a taille 1 ( length(v) == 1 ) Dans ce cas, la valeur v est copié dans chaque place indexé x[i].dizaines
[1] 10 22 30 44 55
dizaines[c(1, 3)] <- -1
dizaines
[1] -1 22 -1 44 55
dizaines < 30
[1] TRUE TRUE TRUE FALSE FALSE
dizaines[dizaines < 30] <- 0
dizaines
[1] 0 0 0 44 55
les deux objets à gauche et à droite de <- ont des tailles différents (length(x[i]) != length(v)). À éviter à touts prix ! Dans ce cas, R décide de:
<- si length(x[i]) > length(v)length(x[i]) < length(v)Cette particularité de R est la cause de nombreux «bugs»… Exemples de recyclage:
dizaines
[1] 0 0 0 44 55
dizaines[1:4] <- c(1,2) # Recyclage sans aucun warning car length(x[i])==4 est un multiple de length(v)==2
dizaines
[1] 1 2 1 2 55
dizaines[1:3] <- c(-1, -2) # Recyclage avec warning: length(x[i])==3 n'est pas un multiple de length(v)==2
Warning in dizaines[1:3] <- c(-1, -2): number of items to replace is not a
multiple of replacement length
dizaines
[1] -1 -2 -1 2 55
dizaines[4:5] <- c(400, 500, 600) # length(x[i])==2, length(v)==3 : Le 600 «de trop» à droite du '<-'
Warning in dizaines[4:5] <- c(400, 500, 600): number of items to replace is not
a multiple of replacement length
# est perdue, avec le même warning
dizaines
[1] -1 -2 -1 400 500
Remarques: L’assignation au point 2 ci-dessus est en effet un cas particulier de recyclage, le seul qui ait du sens! Il faut éviter soigneusement la situation au point 3. C’est quand même important de la connaître, pour dépister les erreurs (surtout dans le cas où on n’a pas de warning).
En somme, pour assigner x[i] <- v
v de la même taille que le résultat de l’indexation x[i]:length(x[i]) == length(v)v de taille 1:length(v) == 1On peut indexer un vecteur en utilisant un index:
entier (integer):
booléen (logical):
TRUE dans l’indexdata.frame ou d’une matriceLa différence avec les vecteurs est que pour un data.frame (ou pour une matrix) on a besoin de deux indices: celui pour les lignes, et celui pour les colonnes.
Pour voir des exemples compréhensibles, plutôt que utiliser un data.frame avec des centaines de lignes, on va créer un simple exemple, avec la fonction data.frame (voir initiation.html):
args(data.frame)
function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,
fix.empty.names = TRUE, stringsAsFactors = default.stringsAsFactors())
NULL
Dans cet exemple, on crée un data frame avec 5 lignes et 3 colonnes, nommées "mots", "nombres" et "romain". Pour le moment on ignore le paramètre stringsAsFactors, on verra sa signification dans la leçon sur les facteurs.
df <- data.frame(mots = c("un","deux","trois","quatre","cinq"),
nombres = 1:5,
romain = c("I","II","III","IV","V"),
stringsAsFactors = FALSE) # les colonnes "character" ne vont pas devenir des facteurs
Voici le résultat, qu’on a assigné à la variable df:
df
mots nombres romain
1 un 1 I
2 deux 2 II
3 trois 3 III
4 quatre 4 IV
5 cinq 5 V
class(df)
[1] "data.frame"
dim(df)
[1] 5 3
str(df)
'data.frame': 5 obs. of 3 variables:
$ mots : chr "un" "deux" "trois" "quatre" ...
$ nombres: int 1 2 3 4 5
$ romain : chr "I" "II" "III" "IV" ...
On va aussi créer un exemple de matrice, contenant les entiers de 1 à 12, par colonne (voir initiation.html):
args(matrix)
function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL)
NULL
La fonction matrix prends un vecteur de valeurs et les dispose par colonne en une matrice nrow x ncol.
m <- matrix(1:12, nrow = 4, ncol = 3)
m
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
class(m)
[1] "matrix"
dim(m)
[1] 4 3
str(m)
int [1:4, 1:3] 1 2 3 4 5 6 7 8 9 10 ...
Soit donc
X un data.frame ou une matrice de m lignes et n colonnes,i un index pour les lignes,j un index pour les colonnes.X[i, j]X[i, ]X[ , j]En somme: le champ qui reste vide n’est pas indexé.
Exemples:
df
mots nombres romain
1 un 1 I
2 deux 2 II
3 trois 3 III
4 quatre 4 IV
5 cinq 5 V
df[2, 3]
[1] "II"
df[2, ]
mots nombres romain
2 deux 2 II
df[, 2]
[1] 1 2 3 4 5
df[, c(1, 3)]
mots romain
1 un I
2 deux II
3 trois III
4 quatre IV
5 cinq V
df[1:3, ]
mots nombres romain
1 un 1 I
2 deux 2 II
3 trois 3 III
df[c(1,3,5), c(TRUE, FALSE, TRUE)]
mots romain
1 un I
3 trois III
5 cinq V
df[c(1,1), c(1,3,2)]
mots romain nombres
1 un I 1
1.1 un I 1
df$nombres >= 4
[1] FALSE FALSE FALSE TRUE TRUE
df[df$nombres >= 4, ]
mots nombres romain
4 quatre 4 IV
5 cinq 5 V
m
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
m[3, 1]
[1] 3
m[2, ]
[1] 2 6 10
m[, 3]
[1] 9 10 11 12
m[2:4, 2:3]
[,1] [,2]
[1,] 6 10
[2,] 7 11
[3,] 8 12
m[c(1, 4), ]
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 4 8 12
m[, c(1, 2, 1)]
[,1] [,2] [,3]
[1,] 1 5 1
[2,] 2 6 2
[3,] 3 7 3
[4,] 4 8 4
Outre à l’indexation par entiers et par booléen, un data frame peut être indexé en utilisant les noms de ses lignes/colonnes.
names(df) # noms des colonnes, classe "character"
[1] "mots" "nombres" "romain"
Moins utilisés: rownames/colnames
colnames(df) # même chose: pour un data.frame "names" et "colnames" donnent le même résultat
[1] "mots" "nombres" "romain"
rownames(df) # noms des lignes, classe "character", par défaut "1", "2", "3", ...
[1] "1" "2" "3" "4" "5"
$df$"mots"
[1] "un" "deux" "trois" "quatre" "cinq"
df$mots
[1] "un" "deux" "trois" "quatre" "cinq"
df$nombres
[1] 1 2 3 4 5
Remarque: avec $, les "" ne sont pas nécessaires, ce qui permets de compléter les noms avec la touche <Tab>.
[]Alternative tidy: utiliser dplyr::select.
Tout comme l’indexation directe, mais avec les noms à la place des nombres. Remarque: ici les "" sont nécessaires:
df[, "mots"] # équivaut à df$mots
[1] "un" "deux" "trois" "quatre" "cinq"
df[, "nombres"] # équivaut à df$nombres
[1] 1 2 3 4 5
df[, c("romain", "nombres")]
romain nombres
1 I 1
2 II 2
3 III 3
4 IV 4
5 V 5
L’avantage par rapport à $ est que dans ce cas on peut utiliser des variables de classe "character", contenants des noms des colonnes qu’on veut sélectionner
index <- "mots"
df[, index]
[1] "un" "deux" "trois" "quatre" "cinq"
index <- c("nombres", "mots")
class(index)
[1] "character"
df[, index]
nombres mots
1 1 un
2 2 deux
3 3 trois
4 4 quatre
5 5 cinq
Indexation des lignes par nom: peu utilisé
df[c("1", "3"), ]
mots nombres romain
1 un 1 I
3 trois 3 III
même résultat que
df[c(1, 3), ]
mots nombres romain
1 un 1 I
3 trois 3 III
Alternative tidy: utiliser dplyr::rename.
Pour changer les noms des lignes/colonnes, on peut leur assigner des nouveaux valeurs, par ex:
df
mots nombres romain
1 un 1 I
2 deux 2 II
3 trois 3 III
4 quatre 4 IV
5 cinq 5 V
rownames(df)
[1] "1" "2" "3" "4" "5"
letters #ce vecteur est défini dans la librairie de base
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x" "y" "z"
letters[1:5]
[1] "a" "b" "c" "d" "e"
rownames(df) <- letters[1:5]
df
mots nombres romain
a un 1 I
b deux 2 II
c trois 3 III
d quatre 4 IV
e cinq 5 V
rownames(df)
[1] "a" "b" "c" "d" "e"
Les exemples suivants fonctionnent aussi en remplaçant “names” avec “colnames”
df
mots nombres romain
a un 1 I
b deux 2 II
c trois 3 III
d quatre 4 IV
e cinq 5 V
names(df)
[1] "mots" "nombres" "romain"
names(df) <- c("M", "N", "R")
df
M N R
a un 1 I
b deux 2 II
c trois 3 III
d quatre 4 IV
e cinq 5 V
names(df)
[1] "M" "N" "R"
On peut aussi indexer les noms, dans le deux cas
names(df)[1:2] <- c("En mots", "En chiffres")
df
En mots En chiffres R
a un 1 I
b deux 2 II
c trois 3 III
d quatre 4 IV
e cinq 5 V
names(df)
[1] "En mots" "En chiffres" "R"
Une matrice aussi peut avoir des noms des lignes/colonnes, accessibles avec rownames et colnames (mais pas names):
rownames(m) <- LETTERS[1:4]
colnames(m) <- letters[1:3]
m
a b c
A 1 5 9
B 2 6 10
C 3 7 11
D 4 8 12
rownames(m)
[1] "A" "B" "C" "D"
colnames(m)
[1] "a" "b" "c"
Pour indexer un data.frame, on peut utiliser les trois façons d’indexer (directe, booléenne, par nom), de façon indépendante pour lignes et colonnes, par exemple, dans notre df restauré:
df <- data.frame(mots = c("un","deux","trois","quatre","cinq"),
nombres = 1:5,
romain = c("I","II","III","IV","V"),
stringsAsFactors = FALSE)
df
mots nombres romain
1 un 1 I
2 deux 2 II
3 trois 3 III
4 quatre 4 IV
5 cinq 5 V
df[df$nombres != 3, ]
mots nombres romain
1 un 1 I
2 deux 2 II
4 quatre 4 IV
5 cinq 5 V
df[df$nombres <= 3, c(2, 1)]
nombres mots
1 1 un
2 2 deux
3 3 trois
df[c(5,3,5), c(2,3)]
nombres romain
5 5 V
3 3 III
5.1 5 V
subsetAlternative tidy: utiliser dplyr::filter et dplyr::select pour indexer lignes et colonnes, respectivement.
En alternative à l’indexation booléenne par ligne, on va utiliser la fonction subset. Cette fonction prends trois arguments, dans l’ordre:
data.frame dont on veut extraire un sous-ensemble des données;subset, qui est un index booléen pour sélectionner un sous-ensemble des lignes;select, optionnel, un index pour sélectionner un sous-ensemble des colonnes (par nom, entier ou booléen).Exemples:
df[df$nombres <= 3, ] # indexation par ligne
mots nombres romain
1 un 1 I
2 deux 2 II
3 trois 3 III
subset(df, nombres <= 3) # même chose, avec subset
mots nombres romain
1 un 1 I
2 deux 2 II
3 trois 3 III
L’avantage de la fonction subset c’est qu’elle permet d’utiliser les noms des colonnes directement dans la condition pour sélectionner les lignes, dans ces exemples nombres plutôt que df$nombres.
subset(df, nombres <= 3, c(2, 1))
nombres mots
1 1 un
2 2 deux
3 3 trois
Pour mieux apprécier l’avantage de subset, on va voir un exemple plus complexe, en utilisant un jeu de données du paquet "questionr":
library("questionr")
data(package = "questionr") #juste pour vérifier le nom des données qui nous intéressent
data("hdv2003")
Voici maintenant un data.frame un peu plus grand, contenant des réponses à un questionnaire de l’INSEE (France).
?hdv2003 # Page d'aide avec lien à l'enquête
class(hdv2003)
[1] "data.frame"
str(hdv2003)
'data.frame': 2000 obs. of 20 variables:
$ id : int 1 2 3 4 5 6 7 8 9 10 ...
$ age : int 28 23 59 34 71 35 60 47 20 28 ...
$ sexe : Factor w/ 2 levels "Homme","Femme": 2 2 1 1 2 2 2 1 2 1 ...
$ nivetud : Factor w/ 8 levels "N'a jamais fait d'etudes",..: 8 NA 3 8 3 6 3 6 NA 7 ...
$ poids : num 2634 9738 3994 5732 4329 ...
$ occup : Factor w/ 7 levels "Exerce une profession",..: 1 3 1 1 4 1 6 1 3 1 ...
$ qualif : Factor w/ 7 levels "Ouvrier specialise",..: 6 NA 3 3 6 6 2 2 NA 7 ...
$ freres.soeurs: int 8 2 2 1 0 5 1 5 4 2 ...
$ clso : Factor w/ 3 levels "Oui","Non","Ne sait pas": 1 1 2 2 1 2 1 2 1 2 ...
$ relig : Factor w/ 6 levels "Pratiquant regulier",..: 4 4 4 3 1 4 3 4 3 2 ...
$ trav.imp : Factor w/ 4 levels "Le plus important",..: 4 NA 2 3 NA 1 NA 4 NA 3 ...
$ trav.satisf : Factor w/ 3 levels "Satisfaction",..: 2 NA 3 1 NA 3 NA 2 NA 1 ...
$ hard.rock : Factor w/ 2 levels "Non","Oui": 1 1 1 1 1 1 1 1 1 1 ...
$ lecture.bd : Factor w/ 2 levels "Non","Oui": 1 1 1 1 1 1 1 1 1 1 ...
$ peche.chasse : Factor w/ 2 levels "Non","Oui": 1 1 1 1 1 1 2 2 1 1 ...
$ cuisine : Factor w/ 2 levels "Non","Oui": 2 1 1 2 1 1 2 2 1 1 ...
$ bricol : Factor w/ 2 levels "Non","Oui": 1 1 1 2 1 1 1 2 1 1 ...
$ cinema : Factor w/ 2 levels "Non","Oui": 1 2 1 2 1 2 1 1 2 2 ...
$ sport : Factor w/ 2 levels "Non","Oui": 1 2 2 2 1 2 1 1 1 2 ...
$ heures.tv : num 0 1 0 2 3 2 2.9 1 2 2 ...
dim(hdv2003) # 2000 observations (répondants) de 20 variables (questions)
[1] 2000 20
summary(hdv2003)
id age sexe
Min. : 1.0 Min. :18.00 Homme: 899
1st Qu.: 500.8 1st Qu.:35.00 Femme:1101
Median :1000.5 Median :48.00
Mean :1000.5 Mean :48.16
3rd Qu.:1500.2 3rd Qu.:60.00
Max. :2000.0 Max. :97.00
nivetud poids
Enseignement technique ou professionnel court :463 Min. : 78.08
Enseignement superieur y compris technique superieur:441 1st Qu.: 2221.82
Derniere annee d'etudes primaires :341 Median : 4631.19
1er cycle :204 Mean : 5535.61
2eme cycle :183 3rd Qu.: 7626.53
(Other) :256 Max. :31092.14
NA's :112
occup qualif freres.soeurs
Exerce une profession:1049 Employe :594 Min. : 0.000
Chomeur : 134 Ouvrier qualifie :292 1st Qu.: 1.000
Etudiant, eleve : 94 Cadre :260 Median : 2.000
Retraite : 392 Ouvrier specialise :203 Mean : 3.283
Retire des affaires : 77 Profession intermediaire:160 3rd Qu.: 5.000
Au foyer : 171 (Other) :144 Max. :22.000
Autre inactif : 83 NA's :347
clso relig
Oui : 936 Pratiquant regulier :266
Non :1037 Pratiquant occasionnel :442
Ne sait pas: 27 Appartenance sans pratique :760
Ni croyance ni appartenance:399
Rejet : 93
NSP ou NVPR : 40
trav.imp trav.satisf hard.rock lecture.bd
Le plus important : 29 Satisfaction :480 Non:1986 Non:1953
Aussi important que le reste:259 Insatisfaction:117 Oui: 14 Oui: 47
Moins important que le reste:708 Equilibre :451
Peu important : 52 NA's :952
NA's :952
peche.chasse cuisine bricol cinema sport heures.tv
Non:1776 Non:1119 Non:1147 Non:1174 Non:1277 Min. : 0.000
Oui: 224 Oui: 881 Oui: 853 Oui: 826 Oui: 723 1st Qu.: 1.000
Median : 2.000
Mean : 2.247
3rd Qu.: 3.000
Max. :12.000
NA's :5
Prenons par exemple le sous-ensemble des femmes retraitées
femmes_retraite <- hdv2003[hdv2003$age >= 65 & hdv2003$sexe == "Femme", ]
dim(femmes_retraite)
[1] 216 20
La même opération avec subset?
femmes_retraite <- subset(hdv2003, age >= 65 & sexe == "Femme")
dputPour indexer le colonnes par nom, on voudrait pouvoir copier/coller plutôt que recopier les noms, pour nous simplifier la vie et éviter des fautes de frappe.
names(df)
[1] "mots" "nombres" "romain"
Copier et éditer le résultat de names va être compliqué. La fonction dput est conçue dans ce but: en général, dput(x) imprime comme résultat une ligne de commande qu’on peut directement copier-coller dans le script pour reconstruire l’objet x.
dput(names(df))
c("mots", "nombres", "romain")
Copier-coller le résultat de dput dans le script, puis effacer les noms sauf ceux qui nous intéressent, nous permets d’éviter les fautes de frappe. Mais, attention aux virgules!
df[df$nombres <= 3, c("mots", "romain")] # indexation par ligne et par colonne
mots romain
1 un I
2 deux II
3 trois III
subset(df, nombres <= 3, c("mots", "romain")) # la même chose, avec subset
mots romain
1 un I
2 deux II
3 trois III
# Pour indexer une seule colonne on peut omettre la fonction `c`
df[df$nombres <= 3, "nombres"]
[1] 1 2 3
subset(df, nombres <= 3, "nombres")
nombres
1 1
2 2
3 3
%in%subset(df, mots == "un" & mots == "trois" ) # ensemble vide!
[1] mots nombres romain
<0 rows> (or 0-length row.names)
Pour sélectionner plusieurs valeurs d’une variable on doit utiliser la disjonction
subset(df, mots == "un" | mots == "trois" )
mots nombres romain
1 un 1 I
3 trois 3 III
Pour plus de deux niveaux ça devient peu lisible et long…
subset(df, mots == "un" | mots == "trois" | mots == "quatre")
mots nombres romain
1 un 1 I
3 trois 3 III
4 quatre 4 IV
Dans ce cas il vaut mieux utiliser l’opérateur d’appartenance \(\in\): en R, %in% (voir slides sur la logique.
"un" %in% c("un","trois","quatre")
[1] TRUE
"deux" %in% c("un","trois","quatre")
[1] FALSE
Remarque: le résultat est un vecteur!
c("un", "deux") %in% c("un","trois","quatre")
[1] TRUE FALSE
En somme on peut utiliser %in% pour sélectionner plusieurs niveaux d’une variable, par exemple:
df
mots nombres romain
1 un 1 I
2 deux 2 II
3 trois 3 III
4 quatre 4 IV
5 cinq 5 V
subset(df, mots %in% c("un","trois","quatre"))
mots nombres romain
1 un 1 I
3 trois 3 III
4 quatre 4 IV
data.frameLes mêmes considérations vues pour les vecteurs valent pour les data.frame, avec la différence que, dans ce cas, il ne s’agit pas de comparer la longueur de deux vecteurs, mais leur dimension, donc nombre de lignes et nombre des colonnes. On peut bien entendu assigner un vecteur de longueur n à une colonne d’un data.frame ayant n lignes.
En somme on a deux cas qui ont du sens:
Attention l’assignation d’une colonne dans un data.frame est sujète aussi au recyclage. L’un des avantages de la classe du tidyverse tibble est d’empecher ceci: tout tentatif d’assigner à une colonne d’un tibble de n ligne un vecteur de longueur différente de 1 ou n genère un erreur.
Exemples avec:
df
mots nombres romain
1 un 1 I
2 deux 2 II
3 trois 3 III
4 quatre 4 IV
5 cinq 5 V
Alternative tidy: rajouter des colonnes avec dplyr::mutate.
letters # Cette variable contient les lettres minuscules
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x" "y" "z"
letters[3]
[1] "c"
letters[1:nrow(df)] # On peut l'utiliser pour créer une nouvelle colonne
[1] "a" "b" "c" "d" "e"
df$lettres # La colonne n'existe pas encore
NULL
class(NULL) # `NULL` est une valeur spéciale qui représente des choses qui n'existent pas
[1] "NULL"
Pour créer une nouvelle colonne, on peut l’indexer à gauche du <-:
df$lettres <- letters[1:nrow(df)]
df
mots nombres romain lettres
1 un 1 I a
2 deux 2 II b
3 trois 3 III c
4 quatre 4 IV d
5 cinq 5 V e
Assignation d’une nouvelle colonne avec un seul valeur (objet de taille 1)
df$zeros <- 0
df
mots nombres romain lettres zeros
1 un 1 I a 0
2 deux 2 II b 0
3 trois 3 III c 0
4 quatre 4 IV d 0
5 cinq 5 V e 0
Avec une indexation, on peut sélectionner d’abord un sous-ensemble des lignes et colonnes, et leur assigner une valeur de taille correspondante
df[c(1, 3, 5), "zeros"]
[1] 0 0 0
df[c(1, 3, 5), "zeros"] <- c(NA, -1, -2)
df
mots nombres romain lettres zeros
1 un 1 I a NA
2 deux 2 II b 0
3 trois 3 III c -1
4 quatre 4 IV d 0
5 cinq 5 V e -2
df[1:3, c("mots", "nombres")] # `3` lignes et `2` colonnes
mots nombres
1 un 1
2 deux 2
3 trois 3
dim(df[1:3, c("mots", "nombres")]) # dimension: `3 2`
[1] 3 2
Si on construit un data.frame avec la même taille (peu importe les noms des colonnes)…
smalldf <- data.frame(m = paste("moins", c("un", "deux", "trois")),
n = c(-1, -2, -3),
stringsAsFactors = FALSE)
smalldf
m n
1 moins un -1
2 moins deux -2
3 moins trois -3
dim(smalldf)
[1] 3 2
str(smalldf)
'data.frame': 3 obs. of 2 variables:
$ m: chr "moins un" "moins deux" "moins trois"
$ n: num -1 -2 -3
…on peut l’assigner à un sous-ensemble des valeurs
df[1:3, c("mots", "nombres")] <- smalldf
df
mots nombres romain lettres zeros
1 moins un -1 I a NA
2 moins deux -2 II b 0
3 moins trois -3 III c -1
4 quatre 4 IV d 0
5 cinq 5 V e -2
Pour l’assignation on ne peut pas utiliser subset.
Alternative tidy: utiliser dplyr::select avec le signe - devant les noms des colonnes à effacer.
Pour éliminer une colonne, on peut lui assigner la valeur NULL
df
mots nombres romain lettres zeros
1 moins un -1 I a NA
2 moins deux -2 II b 0
3 moins trois -3 III c -1
4 quatre 4 IV d 0
5 cinq 5 V e -2
df$nombres <- NULL
df
mots romain lettres zeros
1 moins un I a NA
2 moins deux II b 0
3 moins trois III c -1
4 quatre IV d 0
5 cinq V e -2
df[, c("lettres", "zeros")] <- NULL
df
mots romain
1 moins un I
2 moins deux II
3 moins trois III
4 quatre IV
5 cinq V
dl <- list(nombres = c(0, -1, 2.2), mat = m, dat = df)
dl
$nombres
[1] 0.0 -1.0 2.2
$mat
a b c
A 1 5 9
B 2 6 10
C 3 7 11
D 4 8 12
$dat
mots romain
1 moins un I
2 moins deux II
3 moins trois III
4 quatre IV
5 cinq V
Une liste peut être indexé comme un vecteur, en utilisant [], avec une différence importante: le résultat de l’indexation est encore une liste
dl[1]
$nombres
[1] 0.0 -1.0 2.2
class(dl[1]) # c'est une liste
[1] "list"
length(dl[1]) # de longueur 1
[1] 1
names(dl[1]) # gardant les noms
[1] "nombres"
dl[c(2, 1)]
$mat
a b c
A 1 5 9
B 2 6 10
C 3 7 11
D 4 8 12
$nombres
[1] 0.0 -1.0 2.2
class(dl[c(2, 1)]) # c'est une liste
[1] "list"
length(dl[c(2, 1)]) # de longueur 2
[1] 2
names(dl[c(2, 1)]) # gardant les noms
[1] "mat" "nombres"
Pour obtenir les éléments avec leur classe, il faut utiliser un double crochet:
dl[[1]]
[1] 0.0 -1.0 2.2
class(dl[[1]]) # c'est un vecteur numérique
[1] "numeric"
length(dl[[1]]) # de longueur 3
[1] 3
names(dl[[1]]) # le nom est perdu car les vecteurs n'ont pas de nom
NULL
En autre, une liste peut être indexée par nom, tout comme les colonnes des data frames:
$, permettant d’obtenir directement les éléments:dl$nombres
[1] 0.0 -1.0 2.2
class(dl$nombres) # c'est un vecteur numérique
[1] "numeric"
length(dl$nombres) # de longueur 3
[1] 3
names(dl$nombres) # le nom est perdu car les vecteurs n'ont pas de nom
NULL
dl["nombres"]
$nombres
[1] 0.0 -1.0 2.2
class(dl["nombres"]) # c'est une liste
[1] "list"
length(dl["nombres"]) # de longueur 1
[1] 1
names(dl["nombres"]) # gardant les noms
[1] "nombres"
dl[["nombres"]]
[1] 0.0 -1.0 2.2
class(dl[["nombres"]]) # c'est un vecteur numérique
[1] "numeric"
length(dl[["nombres"]]) # de longueur 3
[1] 3
names(dl[["nombres"]]) # le nom est perdu
NULL
dl[c("mat", "nombres")]
$mat
a b c
A 1 5 9
B 2 6 10
C 3 7 11
D 4 8 12
$nombres
[1] 0.0 -1.0 2.2
class(dl[c("mat", "nombres")]) # c'est une liste
[1] "list"
length(dl[c("mat", "nombres")]) # de longueur 2
[1] 2
names(dl[c("mat", "nombres")]) # gardant les noms
[1] "mat" "nombres"
dl[c(TRUE, FALSE, TRUE)]
$nombres
[1] 0.0 -1.0 2.2
$dat
mots romain
1 moins un I
2 moins deux II
3 moins trois III
4 quatre IV
5 cinq V
class(dl[c(TRUE, FALSE, TRUE)]) # c'est une liste
[1] "list"
length(dl[c(TRUE, FALSE, TRUE)]) # de longueur 2
[1] 2
names(dl[c(TRUE, FALSE, TRUE)]) # gardant les noms
[1] "nombres" "dat"
Remarque: l’indexation par double crochet est limitée aux indices de longueur 1.
dl[1:2] # les deux premiers éléments de la liste, comme prévu
$nombres
[1] 0.0 -1.0 2.2
$mat
a b c
A 1 5 9
B 2 6 10
C 3 7 11
D 4 8 12
L’indexation pour double crochet avec indices de longueur majeure a une signification particulière, et peu intuitive: il s’agit d’une indexation «récursive»:
dl[[1:2]] # deuxième élément du premier élément de la liste
[1] -1
dl[[c(2, 6)]] # sixième élément du deuxième élément de la liste
[1] 6
dl[[c(2, 3, 1)]] # donne erreur car il n'y a pas assez de niveaux
Error in dl[[c(2, 3, 1)]]: recursive indexing failed at level 2
À éviter donc pour questions de clarté.