L’objectif de ce troisième et dernier module est de réutiliser dans un cadre métier les briques élémentaires du langage introduites dans le module précédent:
data.frame
et de ses relations avec les vecteurs, les matrices et les listes;En dernière partie, des liens complémentaires sont fournis vers le support de la formation R perfectionnement ainsi que vers des exemples d’utilisation plus spécifiques du logiciel (analyse de données multidimensionnelle, régression).
data.frame
Dans R, la majeure partie des données statistiques se présente sous la forme de data.frame
: ces objets permettent en effet de représenter sous la forme d’une table (i.e. d’un objet à deux dimensions) des données de nature tant quantitative (variables numériques) que qualitative (variables de type caractère ou facteur).
Pour créer un objet de type data.frame
, il suffit d’utiliser la fonction data.frame()
.
# Création du data.frame df1
df1 <- data.frame(
var1 = 1:10
, var2 = letters[1:10]
, var3 = rep(c(TRUE, FALSE), times = 5)
)
# Caractéristiques de df1
str(df1)
## 'data.frame': 10 obs. of 3 variables:
## $ var1: int 1 2 3 4 5 6 7 8 9 10
## $ var2: Factor w/ 10 levels "a","b","c","d",..: 1 2 3 4 5 6 7 8 9 10
## $ var3: logi TRUE FALSE TRUE FALSE TRUE FALSE ...
# Premières lignes de df1
head(df1)
## var1 var2 var3
## 1 1 a TRUE
## 2 2 b FALSE
## 3 3 c TRUE
## 4 4 d FALSE
## 5 5 e TRUE
## 6 6 f FALSE
Il est impératif que tous les éléments qui composent un data.frame
soient de même longueur.
# Création du data.frame df3
df3 <- data.frame(
var1 = 1:10
, var2 = 1:15
)
## Error in data.frame(var1 = 1:10, var2 = 1:15): les arguments impliquent des nombres de lignes différents : 10, 15
Remarque Par défaut, la fonction data.frame()
convertit les variables caractères en facteurs (cf. module 2). Pour éviter ce comportement (pas toujours souhaitable), il suffit d’utiliser l’argument stringsAsFactors = FALSE
.
# Création du data.frame df2
df2 <- data.frame(
var1 = 1:10
, var2 = letters[1:10]
, var3 = rep(c(TRUE, FALSE), times = 5)
, stringsAsFactors = FALSE
)
# Caractéristiques de df2
str(df2)
## 'data.frame': 10 obs. of 3 variables:
## $ var1: int 1 2 3 4 5 6 7 8 9 10
## $ var2: chr "a" "b" "c" "d" ...
## $ var3: logi TRUE FALSE TRUE FALSE TRUE FALSE ...
# Note : dans df2, var2 est de type caractère alors que dans
# df1 elle a été automatiquement convertie en factor.
Pour empêcher la conversion de caractères en facteurs pour toute une session, il suffit de modifier l’option globale stringsAsFactors
.
# Modification de l'option globale stringsAsFactors
options(stringsAsFactors = FALSE)
# Désormais l'option stringsAsFactors n'est plus nécessaire
# dans chaque appel de fonction
df3 <- data.frame(
var1 = 1:10
, var2 = letters[1:10]
, var3 = rep(c(TRUE, FALSE), times = 5)
)
str(df3)
## 'data.frame': 10 obs. of 3 variables:
## $ var1: int 1 2 3 4 5 6 7 8 9 10
## $ var2: chr "a" "b" "c" "d" ...
## $ var3: logi TRUE FALSE TRUE FALSE TRUE FALSE ...
Du point de vue de sa structure, un data.frame
est en réalité une liste dont tous les éléments ont la même longueur : c’est ce qui permet de le représenter sous la forme d’un tableau à deux dimensions.
# Un data.frame est une liste...
is.list(df1)
## [1] TRUE
# ... dont tous les éléments sont de même longueur
lapply(df1, length)
## $var1
## [1] 10
##
## $var2
## [1] 10
##
## $var3
## [1] 10
De ce fait, les data.frame
empruntent leurs caractéristiques tantôt aux listes, tantôt aux matrices :
Comme une matrice, un data.frame
a deux dimensions (fonction dim()
) ; mais comme une liste, sa longueur (fonction length()
) correspond à son nombre d’éléments (son nombre de variables).
# Dimensions de df1 : comme une matrice
dim(df1)
## [1] 10 3
nrow(df1)
## [1] 10
ncol(df1)
## [1] 3
# Longueur de df1 : comme une liste
length(df1)
## [1] 3
Comme avec une matrice, on accède aux noms de lignes et de colonne d’un data.frame
avec les fonctions rownames()
et colnames()
; mais comme avec une liste, les noms de colonnes sont aussi directement accessibles avec names()
.
# rownames() et colnames() : comme avec une matrice
rownames(df1)
## [1] "1" "2" "3" "4" "5" "6" "7" "8" "9" "10"
colnames(df1)
## [1] "var1" "var2" "var3"
# names() : comme avec une liste
names(df1)
## [1] "var1" "var2" "var3"
Comme avec une matrice, il est possible d’accéder aux éléments d’un data.frame
en indiquant leurs deux positions dans un opérateur [
; mais comme avec une liste, il est également possible d’utiliser les opérateurs [[
et $
.
df1
## var1 var2 var3
## 1 1 a TRUE
## 2 2 b FALSE
## 3 3 c TRUE
## 4 4 d FALSE
## 5 5 e TRUE
## 6 6 f FALSE
## 7 7 g TRUE
## 8 8 h FALSE
## 9 9 i TRUE
## 10 10 j FALSE
# On cherche à accéder à l'élément en ligne 8, colonne 2 de df1
# - comme une matrice : avec `[` et deux positions
df1[8, 2]
## [1] h
## Levels: a b c d e f g h i j
df1[8, "var2"]
## [1] h
## Levels: a b c d e f g h i j
# - comme une liste : avec `[[` pour sélectionner la colonne,
# puis [ pour sélectionner la ligne
df1[[2]][8]
## [1] h
## Levels: a b c d e f g h i j
df1[["var2"]][8]
## [1] h
## Levels: a b c d e f g h i j
# - comme une liste : avec `$` pour sélectionner la colonne,
# puis [ pour sélectionner la ligne
df1$var2[8]
## [1] h
## Levels: a b c d e f g h i j
Les fonctions as.matrix()
, as.list()
et as.data.frame()
permettent de convertir un data.frame
en liste ou en matrice, et inversement.
# Conversion de df1 en matrice
as.matrix(df1)
## var1 var2 var3
## [1,] " 1" "a" " TRUE"
## [2,] " 2" "b" "FALSE"
## [3,] " 3" "c" " TRUE"
## [4,] " 4" "d" "FALSE"
## [5,] " 5" "e" " TRUE"
## [6,] " 6" "f" "FALSE"
## [7,] " 7" "g" " TRUE"
## [8,] " 8" "h" "FALSE"
## [9,] " 9" "i" " TRUE"
## [10,] "10" "j" "FALSE"
# Note : au passage les variables ont toutes été converties
# en caractères, car une matrice ne peut avoir qu'un seul
# et unique type
# Conversion de df1 en liste
as.list(df1)
## $var1
## [1] 1 2 3 4 5 6 7 8 9 10
##
## $var2
## [1] a b c d e f g h i j
## Levels: a b c d e f g h i j
##
## $var3
## [1] TRUE FALSE TRUE FALSE TRUE FALSE TRUE FALSE TRUE FALSE
# Note : on n'a pas à proprement parler affaire ici à une
# "conversion" (un data.frame est une liste) mais plutôt
# à la suppression de certains attributs spécifiques aux
# data.frame (noms de ligne notamment)
rownames(df1)
## [1] "1" "2" "3" "4" "5" "6" "7" "8" "9" "10"
rownames(as.list(df1))
## NULL
# Conversion d'une matrice en data.frame
as.data.frame(matrix(1:10, ncol = 5))
## V1 V2 V3 V4 V5
## 1 1 3 5 7 9
## 2 2 4 6 8 10
# Conversion d'une liste en data.frame
as.data.frame(list(a = 1:5, b = letters[5:1]))
## a b
## 1 1 e
## 2 2 d
## 3 3 c
## 4 4 b
## 5 5 a
# Note : dans ce cas il est également impératif
# que tous les éléments de la liste aient bien la même
# longueur.
Ce cas pratique aborde plusieurs manipulations courantes de sélection de variables et d’observations dans une table. Comme la plupart des cas pratiques de ce module, il repose sur l’utilisation des données de l’enquête Emploi en continu 2012 restreinte au quatrième trimestre et aux individus en première ou sixième interrogation. Ces données correspondent au fichier eect4.rds
contenu dans le fichier donnees.zip.
Après avoir modifié le répertoire de travail avec setwd()
, utilisez la fonction readRDS()
pour charger le fichier eect4.rds
dans l’objet eec
(cf. la remarque finale du module 1 pour l’utilisation de la fonction readRDS()
).
Pour simplifier le travail sur cette table, on souhaite normaliser la casse des noms de variable. Proposez une méthode pour passer l’ensemble des noms de variable en minuscules et appliquez-la.
On souhaite créer deux nouvelles tables ne contenant que les variables sur lesquelles portent différents aspects de l’étude :
eec2
qui ne contienne que les variables ident
, noi
, acteu
et extri1613
.
eec3
qui contienne toutes les variables de eec
à l’exception de cse
.
On souhaite désormais créer une nouvelle table eec4
contenant toutes les variables mais uniquement pour les individus appartenant à la population active (acteu
vaut "1"
ou "2"
). Comment procéderiez-vous ?
data.frame
Pour créer une nouvelle variable dans un data.frame
, le plus simple est d’utiliser l’opérateur $
.
# Création du data.frame df5
df5 <- data.frame(
var1 = letters[1:4]
, var2 = rep(c(FALSE, TRUE), times = 2)
, stringsAsFactors = FALSE
)
df5
## var1 var2
## 1 a FALSE
## 2 b TRUE
## 3 c FALSE
## 4 d TRUE
# Ajout de la variable var3 avec $
df5$var3 <- (1:4)^2
df5
## var1 var2 var3
## 1 a FALSE 1
## 2 b TRUE 4
## 3 c FALSE 9
## 4 d TRUE 16
Pour créer une variable à partir d’une ou plusieurs autres de la table, il suffit d’utiliser l’opérateur $
plusieurs fois.
# Création de la variable var4 à partir de var3
df5$var4 <- df5$var3 * 2
df5
## var1 var2 var3 var4
## 1 a FALSE 1 2
## 2 b TRUE 4 8
## 3 c FALSE 9 18
## 4 d TRUE 16 32
# Conversion de var2 de logique vers numérique
df5$var2 <- as.numeric(df5$var2)
df5
## var1 var2 var3 var4
## 1 a 0 1 2
## 2 b 1 4 8
## 3 c 0 9 18
## 4 d 1 16 32
# Note : modifier à la volée une variable existante ne pose
# aucun problème
Pour effectuer un recodage manuel selon une ou plusieurs conditions (comme un IF THEN ELSE dans SAS), trois méthodes sont disponibles :
Pour les variables dichotomiques uniquement, utiliser des opérateurs logiques pour créer un nouveau vecteur.
# Création de la variable var5 valant TRUE si var4 > 10 et var2 = 1
df5$var5 <- df5$var4 > 10 & df5$var2 == 1
df5
## var1 var2 var3 var4 var5
## 1 a 0 1 2 FALSE
## 2 b 1 4 8 FALSE
## 3 c 0 9 18 FALSE
## 4 d 1 16 32 TRUE
Créer la variable recodée progressivement en utilisant l’opérateur [
.
# Création de la variable var6 identique à var5
df5$var6 <- "Non"
df5$var6[df5$var4 > 10 & df5$var2 == 1] <- "Oui"
df5
## var1 var2 var3 var4 var5 var6
## 1 a 0 1 2 FALSE Non
## 2 b 1 4 8 FALSE Non
## 3 c 0 9 18 FALSE Non
## 4 d 1 16 32 TRUE Oui
Utiliser la fonction ifelse()
.
# Création de la variable var7 identique à var5 et var6
df5$var7 <- ifelse(df5$var4 > 10 & df5$var2 == 1, "Oui", "Non")
df5
## var1 var2 var3 var4 var5 var6 var7
## 1 a 0 1 2 FALSE Non Non
## 2 b 1 4 8 FALSE Non Non
## 3 c 0 9 18 FALSE Non Non
## 4 d 1 16 32 TRUE Oui Oui
La fonction ifelse()
prend trois arguments : l’expression logique à évaluer, la valeur à renvoyer si l’expression est vraie, la valeur à renvoyer si l’expression est fausse. Il est possible d’imbriquer des fonctions ifelse()
pour effectuer des recodages complexes.
Remarque Savoir tirer parti de la fonction within()
Quand on met en oeuvre un recodage, on est fréquemment amené à répéter le nom du data.frame
sur lequel on travaille. La fonction within()
permet d’alléger l’écriture d’un recodage et de faciliter la compréhension d’un code en évitant cette répétition.
# Concaténation manuelle des variables var1 à var4
df5$var7 <- paste0(df5$var1, df5$var2, df5$var3, df5$var4)
# Syntaxe allégée avec la fonction within()
# Création de la variable var5, concaténation de
# toutes les autres variables de la table df5
df5 <- within(df5, {
var8 <- paste0(var1, var2, var3, var4)
})
df5[, c("var7", "var8")]
## var7 var8
## 1 a012 a012
## 2 b148 b148
## 3 c0918 c0918
## 4 d11632 d11632
Le premier argument de within()
est le nom du data.frame
sur lequel porte le recodage, le second est la série d’instructions à appliquer (les accolades sont obligatoires s’il y a plus d’une instruction).
Ce cas pratique vise à appliquer les opérations de création et de modification de variables présentées dans cette partie à des données statistiques classiques. Comme le précédent, il porte sur les données de l’enquête Emploi en continu au 2015T4.
La variable cse
code la Profession et catégorie socioprofessionnelle (PCS) des individus en 42 postes (cf. cette page pour plus de détails). On souhaite créer la variable agrégée cs
qui ne conserve que la première position de la nomenclature.
Proposez une première méthode (un peu fastidieuse) s’appuyant sur des recodages manuels avec l’opérateur [
.
Effectuez le même recodage en utilisant la fonction substr()
.
La variable de position sur le marché du travail (acteu
) comporte des valeurs manquantes dans le fichier eec
à votre disposition. On souhaite imputer cette variable de façon déterministe :
acteu
vaut "1"
) ;acteu
vaut "3"
).Remarque Le fichier original de l’enquête Emploi en continu ne comporte aucune valeur manquante pour la variable acteu
, celles-ci ont été ajoutées pour l’exercice.
Utilisez la fonction table()
pour affichez le nombre de valeurs NA
dans la variable acteu
. Créez la table eec_pb
ne comportant que les individus pour lesquels la variable acteu
vaut NA
.
Dans la table eec
, créez la variable redressée acteu_red
en mettant en oeuvre la procédure d’imputation (très frustre) décrite ci-dessus.
Recréez la table eec_pb
et contrôlez que l’imputation s’est déroulée correctement (en vérifiant que les valeurs imputées sont cohérentes avec l’âge des individus).
Le vecteur de poids de l’enquête (variable extri1613
) présente des valeurs extrêmes relativement élevées. Afin d’éviter que les estimations ne soient trop affectées par quelques individus atypiques, on souhaite limiter le poids des individus en les “rabotant” à la valeur du 99ème percentile.
Utilisez la fonction quantile()
pour calculer le 99ème percentile de la distribution de extri1613
.
Récupérer la valeur du 99ème percentile et utilisez-la pour créer une nouvelle pondération (newpond
) dans laquelle les poids ont été “rabotés” à son niveau.
data.frame
Comme pour les vecteurs ou les matrices, plusieurs opérations permettent de modifier la structure d’un data.frame
:
data.frame
avec order()
: contrairement aux vecteurs, il n’est pas possible d’utiliser la fonction sort()
pour trier un data.frame
. En revanche, la fonction order()
renvoie la permutation permettant de trier une table selon une ou plusieurs variables.# Création de la table df6
df6 <- data.frame(
var1 = letters[c(3, 4, 2, 5, 1, 5, 2, 4, 3, 1)]
, var2 = rnorm(10))
df6
## var1 var2
## 1 c -0.6264538
## 2 d 0.1836433
## 3 b -0.8356286
## 4 e 1.5952808
## 5 a 0.3295078
## 6 e -0.8204684
## 7 b 0.4874291
## 8 d 0.7383247
## 9 c 0.5757814
## 10 a -0.3053884
# Tri selon la variable var1
# - Etape 1 : obtention de la permutation correspondante
order(df6$var1)
## [1] 5 10 3 7 1 9 2 8 4 6
# Utilisée sur le vecteur df6$var1, cette permutation
# renvoie un vecteur trié
df6$var1
## [1] "c" "d" "b" "e" "a" "e" "b" "d" "c" "a"
order(df6$var1)
## [1] 5 10 3 7 1 9 2 8 4 6
df6$var1[order(df6$var1)]
## [1] "a" "a" "b" "b" "c" "c" "d" "d" "e" "e"
# - Etape 2 : utilisation de la permutation pour trier df6
df6[order(df6$var1), ]
## var1 var2
## 5 a 0.3295078
## 10 a -0.3053884
## 3 b -0.8356286
## 7 b 0.4874291
## 1 c -0.6264538
## 9 c 0.5757814
## 2 d 0.1836433
## 8 d 0.7383247
## 4 e 1.5952808
## 6 e -0.8204684
# Tri selon la variable var1 puis la variable var2
# - Etape 1 : obtention de la permutation correspondante
order(df6$var1, df6$var2)
## [1] 10 5 3 7 1 9 2 8 6 4
# - Etape 2 : utilisation de la permutation pour trier
df6[order(df6$var1, df6$var2), ]
## var1 var2
## 10 a -0.3053884
## 5 a 0.3295078
## 3 b -0.8356286
## 7 b 0.4874291
## 1 c -0.6264538
## 9 c 0.5757814
## 2 d 0.1836433
## 8 d 0.7383247
## 6 e -0.8204684
## 4 e 1.5952808
# Tri selon la variable var1 puis les valeurs décroissantes
# de var2
df6 <- df6[order(df6$var1, - df6$var2), ]
df6
## var1 var2
## 5 a 0.3295078
## 10