3.6 Les facteurs
Les facteurs en R sont une structure de données qui permettent de représenter des variables catégorielles. Avant d'aller plus loin, rappelons rapidement de quoi il s'agit. Une variable catégorielle est une variable qui peut prendre un nombre fini de valeurs différentes, comme la couleur des yeux, (vert, bleu, etc), ou encore une appréciation à un diplôme (Passable, Bien, Trés Bien, Excellent).
Les variables catégorielles peuvent être de deux sortes :
- Variable catégorielle ordonnée : Il existe un classement dans l'ordre des différentes catégories. Par exemple pour des mentions a un diplôme, l'ordre serait :
Passable
>Assez Bien
>Bien
>Trés Bien
. - Variable catégorielle non ordonnée : Il n'existe pas de classement hiérchique entre les différentes catégories. Par exemple il est impossible pour la couleur des yeux de dire que
vert
est supérieur àbleu
ou quemarron
.
Les variables catégorielles étant courantes dans l'analyse statistique, il est naturel que R nous permette de les représenter et de les manipuler facilement. Pour cela, R utilise une nouvelle structure de données, les facteurs.
Pourquoi utiliser les facteurs ?
Si on comprend bien que les matrices sont une structure différente des vecteurs qui offrent une nouvelle représentation des données, l'intêret des facteurs semble moins évident aux débutants en R. Pourquoi ne pas simplement utiliser des vecteurs de chaines de caractères ? Est-il vraiment utile de s'embêter avec une nouvelle structure de données ?
Si on s'intéresse à la couleur des yeux de nos étudiants, un vecteur de chaines tel que celui-ci devrait être suffisant non ?
eyes = c("Bleu", "Marron", "Marron", "Vert", "Marron")
Les facteurs ont des avantages qui les rendent incontournables dans la représentation des variables catégorielles par rapport aux vecteurs classiques :
- Il prennent moins de place en mémoire qu'un vecteur. Nous verrons plus tard que cela vient de la façon dont R se représente les facteurs. Gagner de la place en mémoire est important quand on travail sur des ensembles de données importants.
- R sait travailler de façon efficace avec les facteurs, ce qui en rend la manipulation plus efficace que la représentation des mêmes données avec un vecteur de chaines.
- C'est la seule façon de représenter des variables catégorielles ordonnées, comme des mentions à un diplôme. Impossible de faire cela avec des vecteurs sans perdre l'information sur la hiérarchie.
- Et surtout, ils permettent de nativement les utiliser pour une analyse statistique adéquate. Par exemple, réaliser une regression linéaire en transformant automatiquement les facteurs en variables indicatrices (ou dummy variables).
Pour toutes ces raisons, il est indispensable de penser à utiliser des facteurs quand vous voulez représenter des données catégorielles, même si elles ne sont pas ordonnées. R étant un langage pensé pour le traitement de données, il serait stupide de se priver des structures adaptées qu'il offre pour chaque type de données. Vous allez devoir apprendre une nouvelle structure de données, mais cela rendra votre travail bien plus rapide et efficace par la suite.
Créer notre premier facteur
Maintenant que nous avons compris l'intêret des facteurs, essayons de créer notre premier facteur. Commencons par une variable catérielle non ordonnée en nous intérresant à la couleur des yeux de nos étudiants. Pour créer un facteur, il nous faut faire appelle à la fonction factor()
. Cette fonction prend en première paramétre x
un vecteur qui contient les observations de notre variable catégorielle.
eyes = factor(x = c("Bleu", "Marron", "Marron", "Vert", "Marron"))
Il est d'usage d'oublier de nommer le paramètre x
, et d'écrire simplement :
eyes = factor(c("Bleu", "Marron", "Marron", "Vert", "Marron"))
Il est possible de créer un facteur a partir d'un vecteur x
de n'importe quel type. En pratique, on utilisera néanmoins de façon quasi-exclusive des vecteurs de chaines de caractères.
Regardons maintenant la nature de notre nouvelle variable eyes
en interogant sa classe et son type :
La classe de notre variable est factor
, ce qui est plutôt attendu. Si factor
est la classe de notre objet, quel est donc sa nature ?
La nature de notre variable est un vecteur de type integer
! Pourquoi donc utiliser des facteurs au lieu des vecteurs de chaines si les facteurs sont en réalité eux-mêmes des vecteurs de nombres entiers ?
La nature d'un facteur
Un facteur est en réalité un vecteur de nombres entiers, qui est utilisé pour représenter des variables catégorielles. R va simplement affecter un nombre entier unique à chaque valeur possible prise par la variable x
et se souvenir de chaque couleur des yeux comme du nombre associé.
Ici, trois couleurs sont possibles : Bleu
, Marron
et Vert
. R va procéder par ordre alphabétique, et associer le nombre 1
a la couleur Bleu
, 2
pour Marron
et 3
pour Vert
. Il pourra alors retenir le vecteur c(1, 2, 2, 3, 2)
pour représenter le vecteur x
. Cela permet un gain de place en mémoire, ce qui est important quand on travail avec des nombres importants.
Pour vous convaincre de ce gain de place, comparons la mémoire occupée par les deux vecteurs différents :
a = c(1, 2, 2, 3, 2)
b = c("Bleu", "Marron", "Marron", "Vert", "Marron")
On peut trouver le résultat dans l'onglet environment
:
On peut voir que bien que notre vecteur comporte uniquement 5 observations, la forme "réduite" prend 2.75 fois moins de place en mémoire que l'équivent sous forme de chaine de caractères. Si vous travaillez avec des milliers voir des millions d'observations, ce gain en mémoire peut avoir un impact crutial sur les performances.
La propriété levels
Bien entendu, un facteur n'est pas la simple transformation d'un vecteur de type character
en un vecteur de type integer
. En temps qu'humain, nous préferons travailler avec des couleurs comme Bleu
ou Vert
que avec les nombres associés comme 1
et 3
. R va fonc garder en mémoire les différentes valeurs "en lettre" prisent par la variable.
Un facteur se souvient des noms associé à chaque entier via la propriété levels
. Si on affiche un facteur, R nous affiche automatiquement cette propriété levels
:
La première ligne de la console correspond au vecteur x
(en réalité R affiche pour chaque nombre entier le level associé), et la seconde ligne affiche l'ensemble des niveaux (levels) possibles de la variable x
.
Par défaut, l'affichage des niveaux se fait par ordre alphabétique, en fonction de la langue de votre ordinateur. Si votre ordinateur utilise par défaut une langue un peu particulière, vous pouvez donc vous retrouvez avec un résultat différent de l'ordre alphabétique français. On peut aussi choisir l'ordre des levels manuellement, en le spécifiant à la création du facteur via le paramètre levels
:
#On spécifie l'ordre d'affiche des levels à la création avec la propriété levels :
eyes = factor(c("Bleu", "Marron", "Marron", "Vert", "Marron"), levels = c("Marron", "Vert", "Bleu"))
On peut observer le résultat :
Les observations de notre variable n'ont pas changées, mais l'ordre d'affiche des niveaux à changé. Si vous souhaitez uniquement voir les niveaux d'un facteur, vous pouvez utiliser la fonction levels()
:
levels(eyes)
Nous obtennons alors la liste des niveaux pris par notre variable eyes.
Remarque : Le terme level peut être trompeur : il s'agit simplement d'un vecteur qui affiche les différentes valeurs possibles de la variable. Mais cela ne veut pas dire que la valeur qui s'affiche en premier est supérieure à la suivante, ce vecteur n'est pas ordonné par défaut.
Ordonner un facteur
Pour l'instant, notre facteur ne dispose d'aucune hiérarchie entre les différents valeurs (levels). Pour R, Vert
est équivalent à Bleu
. Afin d'introduire un ordre entre les levels d'un facteur, il faut utiliser le paramètreordored
de la fonction factor
. C'est un booléen qui vaut FALSE
par défaut, indiquant que le facteur n'est pas ordonné. Mettons ce paramètre à TRUE
pour ordonner notre facteur.
eyes = factor(c("Bleu", "Marron", "Marron", "Vert", "Marron"),
levels = c("Marron", "Vert", "Bleu"),
ordered = TRUE)
A l'affichage de notre facteur, on remarque la présence de >
a l'affichage des levels qui indiquent l'ordre hiérarchique :
Si vous ne voyez pas ces cheverons dans les levels de votre facteur, c'est un signe indiquant que ce facteur n'est pas ordonné.
La hiérarchie du facteur se fera dans l'ordre indiqué par le paramétrelevels
. Si nous ne voulez pas que la hiérarchie adopte l'ordre alphabétique, qui celui par défaut si levels
n'est pas indiqué, vous devez donc préciciser de façon explique les niveaux de votre facteur via ce paramètre levels
. Et n'oubliez pas de mettre ordered
à TRUE
, levels
seul ne suffit pas à ordonner un facteur !
Comparer des élements d'un facteur
L'intêret principal d'un facteur ordonné est de pouvoir comparer les différentes valeurs qu'il contient. R compare les valeurs de chaque élément en utilisant la hiérarchie des niveaux. Regardons si Marron est supérieur à vert :
eyes[1] > eyes[3]
Oui, marron est bien supérieur à vert, car c'est ainsi que nous avons défini la hiérarchie des levels. Ici, la comparaison n'a pas beaucoup de sens. Mais on peut imaginer utiliser un facteur ordonnée pour mesurer par exemple la proportion d'étudiants qui ont une mention au bac supérieur à la mention bien à partir d'une base de données adéquates.
Manipuler les facteur
Maintenant que nous avons vu comment créer un facteur ordonnée ou non, nous allons voir les bases de la manipulation et modification des facteurs. Pour commencer, rappellons que nous pouvons selectionner des élements dans un facteur avec les mêmes techniques que les vecteurs. A savoir :
- Utiliser un indice positif pour selectionner des éléments :
notes[2]
. - Utiliser un indice négatif pour exclure un élément
notes[-2]
. - Utiliser un vecteur de booléens :
notes[c(TRUE, FALSE)]
.
N'hésitez pas relire le chapitre sur les vecteurs pour vous re-familiariser avec ces méthodes.
Ajouter un élément à un facteur
Pour ajouter un élément à un facteur déjà existant, il n'est pas possible d'utiliser la fonction c()
comme avec les vecteurs. Si vous faites cela, vous allez ajouter ensemble les entiers du facteur avec votre nouvel élément. Pour ajouter un élément à un facteur, il faut simplement écrire le nouvel élément dans un index vide. Notre facteur ayant 4 éléments, l'indice 5 est le premier indice vide :
eyes[5] = "Bleu"
Il n'est possible avec cette méthode que d'ajouter un élément qui est déjà présent dans les levels. Si vous ajouter une valeur qui n'a jamais été rencontrée, alors R refusera de procéder à l'ajout.
Modifier les levels d'un facteur
Il est fréquent que l'on souhaite modifier les levels d'un facteur. Si les données viennent d'une base de données extérieur, on peut vouloir relabaliser nos données pour diverses raisons. Ici, on suppose que l'on aimerai renomer la couleur marron
par noisette
.
Pour faire cela, il suffit d'utiliser de modifier la propriété levels
de notre facteur, et de la remplacée par le nouveau vecteur de levels :
levels(eyes) = c("Noisette", "Vert", "Bleu")
La couleur Marron
à bien été renommée. Il faut attention à bien passer le nouveau vecteur de levels dans l'ordre : le premier élément du vecteur sera associé au premier level, et ainsi de suite ! Cette méthode sert uniquement à changer le nom des levels, et non à les re-ordonner : en essayant de re-ordoner vos facteurs avec, vous échangeriez toutes les observations d'une valeur par une autre valeur de la variable.
N'oubliez pas que toutes les méthodes de selection sur les vecteurs peuvent être utilisées. Cela vous évitera de re-écrire les noms des levels déjà existant, ce qui est peu pratique si vous avez de nombreux niveaux. Re-écrivons notre modification des levels :
new_levels = levels(eyes) #on récupere les niveaux existants
new_levels[1] = "Noisette" #on modifie le premier level
levels(eyes) = new_levels #On remplace les anciens levels par les nouveaux
Nous écrivons deux lignes de code de plus, mais cela reste intéressant si cela nous économise la re-écriture du vecteur des niveaux.
Re-ordonner les facteurs
Un cas de figure fréquent consiste à obtenir un facteur non ordonnée, ou qui n'est pas ordonnée de la bonne façon. C'est très courant quand on charge des données, car les faceurs sont souvent créer non ordonnées, et/ou avec un ordre alphabétique rarement adapté. Il est donc indispensable de pouvoir ordoner ou re-ordonner un facteur existant.
Pour cela, nous suffit de créer un nouveau facteur à partir de l'ancien, et lui indiquer un nouvel ordre des labels, tout en mettant le paramètre ordered
à TRUE
.
eyes = factor(eyes, levels = c("Vert", "Bleu", "Noisette"), ordered = TRUE)
Nos données de notre vecteur x
n'ont pas été modifées, seul l'ordre des levels a été impacté. Le nouvel ordre est maintenant Vert
, Bleu
et Noisette
. Vous pouvez aussi utiliser cette façon de faire simplement pour modifier l'ordre d'affichage des levels d'un facteur non ordonnée, cela fonctionnera aussi.
Conclusion
Nous avons vu dans ce chapitre les principales choses à savoir pour créer et manipuler les facteurs. Les facteurs sont une structure de données indispensable en R, que tout apprenti useR se doit de savoir utiliser. Nous avons dans ce chapitre passé sous silence de nombres choses concernant les facteurs. Par exemple, nous n'avons pas vu comment fusionner ensemble deux facteurs, car R ne propose par défaut pas beaucoup de fonctions pratiques pour travailler avec les facteurs. Heureusement, il existe un package, le package forecats, qui est spécialisé dans l'utilisation avancée des facteurs. Nous apprenderons à utiliser des packages dans quelques chapitres. A ce moment là, vous pourrez regarder du coté de _forecats _pour vous aider à travailler avec les facteurs.
A retenir :
- Les variables catégorielles prennent un nombre de valeurs finies, par oposition aux variables continues. On y trouve les variables catégorielles ordonnées (comme les mentions à un diplôme), et des variables catégorielles non ordonnées (comme la couleur des yeux).
- R utilise les facteurs pour se représenter ces données catégorielles. Un vecteur se créer avec la fonction
factor()
et un vecteur des observations de la variable en question. - Un factor est de classe
factor
mais de typeinteger
. C'est en réalité un vecteur d'entier que R utilise pour stocker l'information. A chaque catégorie possible pour la variable, R affecte un entier uniquement. - Les différentes valeurs/catégories possibles pour le facteur sont disponibles dans la propriété
levels
de l'objet. Par défaut, les niveaux sont classés par ordre alphabétique. On peut spécifier un autre ordre à la création du facteur via la propriétélevels
de la fonctionfactor()
. - Les niveaux n'ont pas de hiérarchie entre eux par défaut, contrairement à ce que leur nom laisse penser. Pour que les niveaux aient une valeur hiérarchique, il faut mettre le paramètre
ordored
de la fonctionfactor()
àTRUE
à la création du facteur. - On peut selectionner une observation d'un facteur avec les mêmes méthodes que les vecteurs car un facteur est fondementalement un vecteur.
- On peut modifier les noms des niveaux via la fonction
levels()
que l'on applique à un facteur et en affectant un nouveau vecteur de levels. - Pour modifier l'ordre des niveaux d'un facteur, il faut redéfinir ce facteur en indiquant le nouvel ordre via la propriété
levels
de la fonctionfactor()
.