R Language
Facteurs
Recherche…
Syntaxe
- facteur (x = caractère (), niveaux, libellés = niveaux, exclure = NA, ordonné = est.ordonné (x), nmax = NA)
- Exécuter
?factor
ou voir la documentation en ligne.
Remarques
Un objet avec factor
classe est un vecteur avec un ensemble particulier de caractéristiques.
- Il est stocké en interne sous forme de vecteur
integer
. - Il conserve un attribut de
levels
qui indique la représentation des valeurs par les caractères. - Sa classe est stockée comme
factor
Pour illustrer, générons un vecteur de 1 000 observations à partir d’un ensemble de couleurs.
set.seed(1)
Color <- sample(x = c("Red", "Blue", "Green", "Yellow"),
size = 1000,
replace = TRUE)
Color <- factor(Color)
Nous pouvons observer chacune des caractéristiques de la Color
énumérées ci-dessus:
#* 1. It is stored internally as an `integer` vector
typeof(Color)
[1] "integer"
#* 2. It maintains a `levels` attribute the shows the character representation of the values.
#* 3. Its class is stored as `factor`
attributes(Color)
$levels [1] "Blue" "Green" "Red" "Yellow" $class [1] "factor"
Le principal avantage d'un objet factor est l'efficacité du stockage des données. Un entier nécessite moins de mémoire à stocker qu'un caractère. Une telle efficacité était hautement souhaitable lorsque de nombreux ordinateurs avaient des ressources beaucoup plus limitées que les machines actuelles (pour un historique plus détaillé des motivations derrière l'utilisation de facteurs, voir stringsAsFactors
: une biographie non autorisée ). La différence d'utilisation de la mémoire peut être vue même dans notre objet Color
. Comme vous pouvez le voir, stocker la Color
tant que caractère nécessite environ 1,7 fois plus de mémoire que l’objet factor.
#* Amount of memory required to store Color as a factor.
object.size(Color)
4624 bytes
#* Amount of memory required to store Color as a character
object.size(as.character(Color))
8232 bytes
Mapper l'entier au niveau
Alors que le calcul interne des facteurs considère l'objet comme un entier, la représentation souhaitée pour la consommation humaine est le niveau de caractère. Par exemple,
head(Color)
[1] Blue Blue Green Yellow Red Yellow Levels: Blue Green Red Yellow
est plus facile pour la compréhension humaine que
head(as.numeric(Color))
[1] 1 1 2 4 3 4
Une illustration approximative de la manière dont R correspond à la représentation des caractères à la valeur entière interne est:
head(levels(Color)[as.numeric(Color)])
[1] "Blue" "Blue" "Green" "Yellow" "Red" "Yellow"
Comparez ces résultats à
head(Color)
[1] Blue Blue Green Yellow Red Yellow Levels: Blue Green Red Yellow
Utilisation moderne des facteurs
En 2007, R a introduit une méthode de hachage des caractères pour réduire la charge de mémoire des vecteurs de caractères (réf: stringsAsFactors
: une biographie non autorisée ). Notez que lorsque nous avons déterminé que les caractères nécessitaient 1,7 fois plus d'espace de stockage que les facteurs, cela a été calculé dans une version récente de R, ce qui signifie que l'utilisation de mémoire des vecteurs de caractères était encore plus lourde avant 2007.
En raison de la méthode de hachage dans le R moderne et de ressources de mémoire beaucoup plus importantes dans les ordinateurs modernes, le problème de l'efficacité de la mémoire dans le stockage des valeurs de caractère a été réduit à un très petit souci. L'attitude qui prévaut dans la communauté R est une préférence pour les vecteurs de caractères par rapport aux facteurs dans la plupart des situations. Les principales causes de l'abandon des facteurs sont
- L'augmentation des données de caractères non structurées et / ou faiblement contrôlées
- La tendance des facteurs à ne pas se comporter comme souhaité lorsque l'utilisateur oublie qu'il a affaire à un facteur et non à un caractère
Dans le premier cas, il est inutile de stocker du texte libre ou des champs de réponse ouverts en tant que facteurs, car il est peu probable qu'un motif autorise plus d'une observation par niveau. Alternativement, si la structure des données n'est pas soigneusement contrôlée, il est possible d'obtenir plusieurs niveaux correspondant à la même catégorie (tels que "bleu", "bleu" et "BLEU"). Dans de tels cas, beaucoup préfèrent gérer ces écarts en tant que caractères avant de les convertir en facteurs (si la conversion a lieu).
Dans le second cas, si l'utilisateur pense travailler avec un vecteur de caractères, certaines méthodes peuvent ne pas répondre comme prévu. Cette compréhension de base peut entraîner de la confusion et de la frustration en essayant de déboguer des scripts et des codes. Bien que, à proprement parler, cela puisse être considéré comme la faute de l'utilisateur, la plupart des utilisateurs sont heureux d'éviter d'utiliser des facteurs et d'éviter complètement ces situations.
Création de base de facteurs
Les facteurs sont un moyen de représenter les variables catégorielles dans R. Un facteur est stocké en interne en tant que vecteur d'entiers . Les éléments uniques du vecteur de caractère fourni sont appelés les niveaux du facteur. Par défaut, si les niveaux ne sont pas fournis par l'utilisateur, alors R génère l'ensemble des valeurs uniques dans le vecteur, trie ces valeurs par ordre alphanumérique et les utilise comme niveaux.
charvar <- rep(c("n", "c"), each = 3)
f <- factor(charvar)
f
levels(f)
> f
[1] n n n c c c
Levels: c n
> levels(f)
[1] "c" "n"
Si vous souhaitez modifier l'ordre des niveaux, une option permet de spécifier les niveaux manuellement:
levels(factor(charvar, levels = c("n","c")))
> levels(factor(charvar, levels = c("n","c")))
[1] "n" "c"
Les facteurs ont un certain nombre de propriétés. Par exemple, les niveaux peuvent recevoir des étiquettes:
> f <- factor(charvar, levels=c("n", "c"), labels=c("Newt", "Capybara"))
> f
[1] Newt Newt Newt Capybara Capybara Capybara
Levels: Newt Capybara
Une autre propriété pouvant être attribuée est de savoir si le facteur est commandé:
> Weekdays <- factor(c("Monday", "Wednesday", "Thursday", "Tuesday", "Friday", "Sunday", "Saturday"))
> Weekdays
[1] Monday Wednesday Thursday Tuesday Friday Sunday Saturday
Levels: Friday Monday Saturday Sunday Thursday Tuesday Wednesday
> Weekdays <- factor(Weekdays, levels=c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"), ordered=TRUE)
> Weekdays
[1] Monday Wednesday Thursday Tuesday Friday Sunday Saturday
Levels: Monday < Tuesday < Wednesday < Thursday < Friday < Saturday < Sunday
Lorsqu'un niveau du facteur n'est plus utilisé, vous pouvez le déposer en utilisant la fonction droplevels()
:
> Weekend <- subset(Weekdays, Weekdays == "Saturday" | Weekdays == "Sunday")
> Weekend
[1] Sunday Saturday
Levels: Monday < Tuesday < Wednesday < Thursday < Friday < Saturday < Sunday
> Weekend <- droplevels(Weekend)
> Weekend
[1] Sunday Saturday
Levels: Saturday < Sunday
Consolidation des niveaux de facteurs avec une liste
Il y a des moments où il est souhaitable de consolider les niveaux de facteurs en moins de groupes, peut-être en raison de la rareté des données dans l'une des catégories. Cela peut également se produire lorsque vous avez des orthographes ou des majuscules variables pour les noms de catégories. Prenons comme exemple le facteur
set.seed(1)
colorful <- sample(c("red", "Red", "RED", "blue", "Blue", "BLUE", "green", "gren"),
size = 20,
replace = TRUE)
colorful <- factor(colorful)
Puisque R est sensible à la casse, une table de fréquence de ce vecteur apparaîtra comme ci-dessous.
table(colorful)
colorful blue Blue BLUE green gren red Red RED 3 1 4 2 4 1 3 2
Ce tableau, cependant, ne représente pas la distribution réelle des données et les catégories peuvent être réduites à trois types: bleu, vert et rouge. Trois exemples sont fournis. La première illustre ce qui semble être une solution évidente, mais ne fournira pas de solution. La seconde donne une solution de travail, mais est coûteuse et verbeuse. La troisième n'est pas une solution évidente, mais elle est relativement compacte et efficace en termes de calcul.
Consolidation des niveaux à l'aide du factor
( factor_approach
factor
)
factor(as.character(colorful),
levels = c("blue", "Blue", "BLUE", "green", "gren", "red", "Red", "RED"),
labels = c("Blue", "Blue", "Blue", "Green", "Green", "Red", "Red", "Red"))
[1] Green Blue Red Red Blue Red Red Red Blue Red Green Green Green Blue Red Green [17] Red Green Green Red Levels: Blue Blue Blue Green Green Red Red Red Warning message: In `levels<-`(`*tmp*`, value = if (nl == nL) as.character(labels) else paste0(labels, : duplicated levels in factors are deprecated
Notez qu'il existe des niveaux dupliqués. Nous avons toujours trois catégories pour "Blue", ce qui ne complète pas notre tâche de consolidation des niveaux. En outre, il existe un avertissement indiquant que les niveaux dupliqués sont obsolètes, ce qui signifie que ce code peut générer une erreur à l'avenir.
Consolidation des niveaux à l'aide de ifelse
( ifelse_approach
)
factor(ifelse(colorful %in% c("blue", "Blue", "BLUE"),
"Blue",
ifelse(colorful %in% c("green", "gren"),
"Green",
"Red")))
[1] Green Blue Red Red Blue Red Red Red Blue Red Green Green Green Blue Red Green [17] Red Green Green Red Levels: Blue Green Red
Ce code génère le résultat souhaité, mais nécessite l'utilisation d'instructions ifelse
imbriquées. Bien qu'il n'y ait rien de mal à cette approche, la gestion des instructions ifelse
imbriquées peut être une tâche fastidieuse et doit être effectuée avec soin.
Consolidation des niveaux de facteurs avec une liste ( list_approach
)
Une manière moins évidente de consolider les niveaux consiste à utiliser une liste où le nom de chaque élément correspond au nom de la catégorie souhaitée et où l’élément est un vecteur de caractère des niveaux du facteur qui doivent correspondre à la catégorie souhaitée. Cela présente l'avantage supplémentaire de travailler directement sur l'attribut levels
du facteur, sans devoir affecter de nouveaux objets.
levels(colorful) <-
list("Blue" = c("blue", "Blue", "BLUE"),
"Green" = c("green", "gren"),
"Red" = c("red", "Red", "RED"))
[1] Green Blue Red Red Blue Red Red Red Blue Red Green Green Green Blue Red Green [17] Red Green Green Red Levels: Blue Green Red
Benchmarking chaque approche
Le temps requis pour exécuter chacune de ces approches est résumé ci-dessous. (Par souci d’espace, le code pour générer ce résumé n’est pas affiché)
Unit: microseconds expr min lq mean median uq max neval cld factor 78.725 83.256 93.26023 87.5030 97.131 218.899 100 b ifelse 104.494 107.609 123.53793 113.4145 128.281 254.580 100 c list_approach 49.557 52.955 60.50756 54.9370 65.132 138.193 100 a
L'approche de la liste est environ deux fois plus rapide que celle de l'approche ifelse
. Cependant, sauf en cas de très, très grande quantité de données, les différences de temps d'exécution seront probablement mesurées en microsecondes ou en millisecondes. Avec de si petites différences de temps, l'efficacité ne doit pas guider la décision de l'approche à utiliser. Au lieu de cela, utilisez une approche familière et confortable que vous et vos collaborateurs comprendrez lors de futures révisions.
Facteurs
Les facteurs sont une méthode pour représenter des variables catégorielles dans R. Étant donné un vecteur x
dont les valeurs peuvent être converties en caractères à l'aide de as.character()
, les arguments par défaut de factor()
et as.factor()
affectent un entier à chaque élément distinct de le vecteur ainsi qu'un attribut level et un attribut label. Les niveaux sont les valeurs que x
peuvent éventuellement prendre et les étiquettes peuvent être soit l'élément donné, soit déterminé par l'utilisateur.
Pour illustrer le fonctionnement des facteurs, nous allons créer un facteur avec des attributs par défaut, puis des niveaux personnalisés, puis des niveaux et des étiquettes personnalisés.
# standard
factor(c(1,1,2,2,3,3))
[1] 1 1 2 2 3 3
Levels: 1 2 3
Des situations peuvent survenir lorsque l'utilisateur sait que le nombre de valeurs possibles qu'un facteur peut prendre est supérieur aux valeurs actuelles du vecteur. Pour cela, nous affectons nous-mêmes les niveaux dans factor()
.
factor(c(1,1,2,2,3,3),
levels = c(1,2,3,4,5))
[1] 1 1 2 2 3 3
Levels: 1 2 3 4 5
À des fins de style, l'utilisateur peut souhaiter attribuer des étiquettes à chaque niveau. Par défaut, les étiquettes sont la représentation des caractères des niveaux. Ici, nous attribuons des étiquettes pour chacun des niveaux possibles dans le facteur.
factor(c(1,1,2,2,3,3),
levels = c(1,2,3,4,5),
labels = c("Fox","Dog","Cow","Brick","Dolphin"))
[1] Fox Fox Dog Dog Cow Cow
Levels: Fox Dog Cow Brick Dolphin
Normalement, les facteurs ne peuvent être comparés qu'en utilisant ==
et !=
Et si les facteurs ont les mêmes niveaux. La comparaison des facteurs ci-après échoue même s'ils semblent égaux car les facteurs ont des niveaux de facteurs différents.
factor(c(1,1,2,2,3,3),levels = c(1,2,3)) == factor(c(1,1,2,2,3,3),levels = c(1,2,3,4,5))
Error in Ops.factor(factor(c(1, 1, 2, 2, 3, 3), levels = c(1, 2, 3)), :
level sets of factors are different
Cela a du sens car les niveaux supplémentaires dans le RHS signifient que R ne dispose pas de suffisamment d'informations sur chaque facteur pour les comparer de manière significative.
Les opérateurs <
, <=
, >
et >=
ne sont utilisables que pour les facteurs ordonnés. Ceux-ci peuvent représenter des valeurs catégoriques qui ont toujours un ordre linéaire. Un facteur ordonné peut être créé en fournissant l'argument ordered = TRUE
à la fonction factor
ou en utilisant simplement la fonction ordered
.
x <- factor(1:3, labels = c('low', 'medium', 'high'), ordered = TRUE)
print(x)
[1] low medium high
Levels: low < medium < high
y <- ordered(3:1, labels = c('low', 'medium', 'high'))
print(y)
[1] high medium low
Levels: low < medium < high
x < y
[1] TRUE FALSE FALSE
Pour plus d'informations, consultez la documentation Factor .
Changement et réorganisation des facteurs
Lorsque des facteurs sont créés avec des valeurs par défaut, les levels
sont formés par as.character
appliqué aux entrées et sont classés par ordre alphabétique.
charvar <- rep(c("W", "n", "c"), times=c(17,20,14))
f <- factor(charvar)
levels(f)
# [1] "c" "n" "W"
Dans certaines situations, le traitement de l'ordre par défaut des levels
(ordre alphabétique / lexical) sera acceptable. Par exemple, si on veut plot
les fréquences, ce sera le résultat:
plot(f,col=1:length(levels(f)))
Mais si nous voulons un ordre de levels
, nous devons le spécifier dans le paramètre levels
ou labels
(en veillant à ce que la signification de "order" soit différente des facteurs ordonnés , voir ci-dessous). Il existe de nombreuses alternatives pour accomplir cette tâche en fonction de la situation.
1. Redéfinir le facteur
Lorsque cela est possible, nous pouvons recréer le facteur en utilisant le paramètre levels
avec l’ordre que nous voulons.
ff <- factor(charvar, levels = c("n", "W", "c"))
levels(ff)
# [1] "n" "W" "c"
gg <- factor(charvar, levels = c("W", "c", "n"))
levels(gg)
# [1] "W" "c" "n"
Lorsque les niveaux d'entrée sont différents des niveaux de sortie souhaités, nous utilisons le paramètre labels
qui fait que le paramètre levels
devient un "filtre" pour les valeurs d'entrée acceptables, mais laisse les valeurs finales des "level" pour le vecteur factor comme argument de labels
:
fm <- factor(as.numeric(f),levels = c(2,3,1),
labels = c("nn", "WW", "cc"))
levels(fm)
# [1] "nn" "WW" "cc"
fm <- factor(LETTERS[1:6], levels = LETTERS[1:4], # only 'A'-'D' as input
labels = letters[1:4]) # but assigned to 'a'-'d'
fm
#[1] a b c d <NA> <NA>
#Levels: a b c d
2. Utilisez la fonction relevel
Quand il y a un level
spécifique qui doit être le premier, nous pouvons utiliser relevel
. Cela se produit, par exemple, dans le contexte de l'analyse statistique, lorsqu'une catégorie de base
est nécessaire pour tester l'hypothèse.
g<-relevel(f, "n") # moves n to be the first level
levels(g)
# [1] "n" "c" "W"
Comme on peut le vérifier, f
et g
sont les mêmes
all.equal(f, g)
# [1] "Attributes: < Component “levels”: 2 string mismatches >"
all.equal(f, g, check.attributes = F)
# [1] TRUE
3. Facteurs de réorganisation
Il y a des cas où nous devons reorder
les levels
fonction d'un nombre, d'un résultat partiel, d'une statistique calculée ou de calculs antérieurs. Réordonnons en fonction des fréquences des levels
table(g)
# g
# n c W
# 20 14 17
La fonction de reorder
est générique (voir help(reorder)
), mais dans ce contexte, il faut: x
, dans ce cas le facteur; X
, une valeur numérique de même longueur que x
; et FUN
, une fonction à appliquer à X
et calculée par niveau du x
, qui détermine l'ordre des levels
, par défaut croissant. Le résultat est le même facteur avec ses niveaux réorganisés.
g.ord <- reorder(g,rep(1,length(g)), FUN=sum) #increasing
levels(g.ord)
# [1] "c" "W" "n"
Pour obtenir un ordre décroissant, nous considérons des valeurs négatives ( -1
)
g.ord.d <- reorder(g,rep(-1,length(g)), FUN=sum)
levels(g.ord.d)
# [1] "n" "W" "c"
Encore une fois, le facteur est le même que les autres.
data.frame(f,g,g.ord,g.ord.d)[seq(1,length(g),by=5),] #just same lines
# f g g.ord g.ord.d
# 1 W W W W
# 6 W W W W
# 11 W W W W
# 16 W W W W
# 21 n n n n
# 26 n n n n
# 31 n n n n
# 36 n n n n
# 41 c c c c
# 46 c c c c
# 51 c c c c
Lorsqu'il existe une variable quantitative liée à la variable facteur, nous pourrions utiliser d'autres fonctions pour réorganiser les levels
. Prenons les données de l' iris
( help("iris")
pour plus d'informations), pour réorganiser le facteur Species
en utilisant son Sepal.Width
moyen.
miris <- iris #help("iris") # copy the data
with(miris, tapply(Sepal.Width,Species,mean))
# setosa versicolor virginica
# 3.428 2.770 2.974
miris$Species.o<-with(miris,reorder(Species,-Sepal.Width))
levels(miris$Species.o)
# [1] "setosa" "virginica" "versicolor"
Les boxplot
habituelles (disons: with(miris, boxplot(Petal.Width~Species)
) montreront les espèces dans cet ordre: setosa , versicolor et virginica, mais en utilisant le facteur ordonné, nous obtenons les espèces classées par Sepal.Width
:
boxplot(Petal.Width~Species.o, data = miris,
xlab = "Species", ylab = "Petal Width",
main = "Iris Data, ordered by mean sepal width", varwidth = TRUE,
col = 2:4)
En outre, il est également possible de modifier les noms de levels
, de les combiner en groupes ou d’ajouter de nouveaux levels
. Pour cela , nous utilisons la fonction du même nom levels
.
f1<-f
levels(f1)
# [1] "c" "n" "W"
levels(f1) <- c("upper","upper","CAP") #rename and grouping
levels(f1)
# [1] "upper" "CAP"
f2<-f1
levels(f2) <- c("upper","CAP", "Number") #add Number level, which is empty
levels(f2)
# [1] "upper" "CAP" "Number"
f2[length(f2):(length(f2)+5)]<-"Number" # add cases for the new level
table(f2)
# f2
# upper CAP Number
# 33 17 6
f3<-f1
levels(f3) <- list(G1 = "upper", G2 = "CAP", G3 = "Number") # The same using list
levels(f3)
# [1] "G1" "G2" "G3"
f3[length(f3):(length(f3)+6)]<-"G3" ## add cases for the new level
table(f3)
# f3
# G1 G2 G3
# 33 17 7
- facteurs ordonnés
Enfin, nous savons que les facteurs ordered
sont différents des factors
, le premier est utilisé pour représenter les données ordinales et le second pour les données nominales . Au début, il n'est pas logique de modifier l'ordre des levels
pour les facteurs ordonnés, mais nous pouvons changer ses labels
.
ordvar<-rep(c("Low", "Medium", "High"), times=c(7,2,4))
of<-ordered(ordvar,levels=c("Low", "Medium", "High"))
levels(of)
# [1] "Low" "Medium" "High"
of1<-of
levels(of1)<- c("LOW", "MEDIUM", "HIGH")
levels(of1)
# [1] "LOW" "MEDIUM" "HIGH"
is.ordered(of1)
# [1] TRUE
of1
# [1] LOW LOW LOW LOW LOW LOW LOW MEDIUM MEDIUM HIGH HIGH HIGH HIGH
# Levels: LOW < MEDIUM < HIGH
Reconstruire les facteurs à partir de zéro
Problème
Les facteurs sont utilisés pour représenter des variables qui prennent des valeurs d'un ensemble de catégories, appelées Niveaux dans R. Par exemple, certaines expériences peuvent être caractérisées par le niveau d'énergie d'une batterie, avec quatre niveaux: vide, faible, normal et plein. Ensuite, pour 5 sites d'échantillonnage différents, ces niveaux pourraient être identifiés comme suit:
plein , plein , normal , vide , bas
Généralement, dans les bases de données ou d'autres sources d'informations, le traitement de ces données se fait par des indices entiers arbitraires associés aux catégories ou aux niveaux. Si nous supposons que, pour l'exemple donné, nous affecterions les indices comme suit: 1 = vide, 2 = faible, 3 = normal, 4 = plein, alors les 5 échantillons pourraient être codés comme suit:
4 , 4 , 3 , 1 , 2
Il se peut que, à partir de votre source d'informations, par exemple une base de données, vous ne disposez que de la liste codée d'entiers et du catalogue associant chaque entier à chaque mot-clé de niveau. Comment reconstruire un facteur de R à partir de cette information?
Solution
Nous allons simuler un vecteur de 20 nombres entiers représentant les échantillons, chacun pouvant avoir l'une des quatre valeurs suivantes:
set.seed(18)
ii <- sample(1:4, 20, replace=T)
ii
[1] 4 3 4 1 1 3 2 3 2 1 3 4 1 2 4 1 3 1 4 1
La première étape consiste à prendre en compte, à partir de la séquence précédente, les niveaux ou catégories correspondant exactement aux chiffres de 1 à 4.
fii <- factor(ii, levels=1:4) # it is necessary to indicate the numeric levels
fii
[1] 4 3 4 1 1 3 2 3 2 1 3 4 1 2 4 1 3 1 4 1
Niveaux: 1 2 3 4
Maintenant, vous devez simplement habiller le facteur déjà créé avec les balises index:
levels(fii) <- c("empty", "low", "normal", "full")
fii
[1] normal normal complet vide vide normal bas normal bas vide
[11] normal plein vide bas plein vide normal vide plein vide
Niveaux: vide bas normal complet