Recherche…


Syntaxe

  1. facteur (x = caractère (), niveaux, libellés = niveaux, exclure = NA, ordonné = est.ordonné (x), nmax = NA)
  2. 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.

  1. Il est stocké en interne sous forme de vecteur integer .
  2. Il conserve un attribut de levels qui indique la représentation des valeurs par les caractères.
  3. 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

  1. L'augmentation des données de caractères non structurées et / ou faiblement contrôlées
  2. 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)))

entrer la description de l'image ici

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) 

entrer la description de l'image ici

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



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow