Buscar..


Sintaxis

  1. factor (x = carácter (), niveles, etiquetas = niveles, excluir = NA, ordenado = ordenado (x), nmax = NA)
  2. Ejecutar el ?factor o ver la documentación en línea.

Observaciones

Un objeto con factor clase es un vector con un conjunto particular de características.

  1. Se almacena internamente como un vector integer .
  2. Mantiene un atributo de levels muestra la representación de caracteres de los valores.
  3. Su clase se almacena como factor

Para ilustrar, generemos un vector de 1,000 observaciones de un conjunto de colores.

set.seed(1)
Color <- sample(x = c("Red", "Blue", "Green", "Yellow"), 
                size = 1000, 
                replace = TRUE)
Color <- factor(Color)

Podemos observar cada una de las características de Color enumeradas anteriormente:

#* 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"

La principal ventaja de un objeto factorial es la eficiencia en el almacenamiento de datos. Un entero requiere menos memoria para almacenar que un carácter. Dicha eficiencia era altamente deseable cuando muchas computadoras tenían recursos mucho más limitados que las máquinas actuales (para una historia más detallada de las motivaciones detrás de los factores de uso, vea stringsAsFactors : una biografía no autorizada ). La diferencia en el uso de la memoria se puede ver incluso en nuestro objeto Color . Como puede ver, el almacenamiento de Color como un carácter requiere aproximadamente 1,7 veces más memoria que el objeto 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

Mapeo del entero al nivel

Mientras que el cálculo interno de los factores ve el objeto como un entero, la representación deseada para el consumo humano es el nivel de carácter. Por ejemplo,

head(Color)
[1] Blue   Blue   Green  Yellow Red    Yellow  
Levels: Blue Green Red Yellow

Es más fácil para la comprensión humana que

head(as.numeric(Color))
[1] 1 1 2 4 3 4

Una ilustración aproximada de cómo R va haciendo coincidir la representación de caracteres con el valor entero interno es:

head(levels(Color)[as.numeric(Color)])
[1] "Blue"   "Blue"   "Green"  "Yellow" "Red"    "Yellow"

Compara estos resultados con

head(Color)
[1] Blue   Blue   Green  Yellow Red    Yellow  
Levels: Blue Green Red Yellow

Uso moderno de los factores.

En 2007, R introdujo un método de hashing para caracteres que reducía la carga de memoria de los vectores de caracteres (ref: stringsAsFactors : una biografía no autorizada ). Tenga en cuenta que cuando determinamos que los caracteres requieren 1.7 veces más espacio de almacenamiento que los factores, eso se calculó en una versión reciente de R, lo que significa que el uso de la memoria de los vectores de caracteres fue aún más exigente antes de 2007.

Debido al método hash en la R moderna y a recursos de memoria mucho mayores en las computadoras modernas, el problema de la eficiencia de la memoria en el almacenamiento de valores de caracteres se ha reducido a una preocupación muy pequeña. La actitud predominante en la comunidad R es una preferencia por los vectores de caracteres sobre los factores en la mayoría de las situaciones. Las causas principales para el alejamiento de los factores son

  1. El aumento de datos de caracteres no estructurados y / o poco controlados.
  2. La tendencia de los factores a no comportarse como se desea cuando el usuario olvida que está tratando con un factor y no con un personaje.

En el primer caso, no tiene sentido almacenar texto libre o campos de respuesta abiertos como factores, ya que es poco probable que haya algún patrón que permita más de una observación por nivel. Alternativamente, si la estructura de datos no se controla cuidadosamente, es posible obtener múltiples niveles que se correspondan con la misma categoría (como "azul", "azul" y "AZUL"). En tales casos, muchos prefieren administrar estas discrepancias como caracteres antes de convertirse en un factor (si la conversión se lleva a cabo).

En el segundo caso, si el usuario piensa que está trabajando con un vector de caracteres, es posible que ciertos métodos no respondan según lo previsto. Esta comprensión básica puede generar confusión y frustración al intentar depurar scripts y códigos. Mientras que, estrictamente hablando, esto puede ser considerado culpa del usuario, la mayoría de los usuarios están felices de evitar el uso de factores y evitar estas situaciones por completo.

Creación básica de factores.

Los factores son una forma de representar variables categóricas en R. Un factor se almacena internamente como un vector de enteros . Los elementos únicos del vector de caracteres suministrados se conocen como los niveles del factor. De forma predeterminada, si los niveles no son suministrados por el usuario, R generará el conjunto de valores únicos en el vector, ordena estos valores de forma alfanumérica y los utiliza como niveles.

 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 desea cambiar el orden de los niveles, una opción para especificar los niveles manualmente:

levels(factor(charvar, levels = c("n","c")))

> levels(factor(charvar, levels = c("n","c")))
[1] "n" "c"

Los factores tienen una serie de propiedades. Por ejemplo, a los niveles se les puede dar etiquetas:

> f <- factor(charvar, levels=c("n", "c"), labels=c("Newt", "Capybara"))
> f
[1] Newt     Newt     Newt     Capybara Capybara Capybara
Levels: Newt Capybara

Otra propiedad que se puede asignar es si el factor está ordenado:

> 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

Cuando ya no se usa un nivel del factor, puede eliminarlo usando la función 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

Consolidación de niveles de factor con una lista

Hay momentos en que es deseable consolidar los niveles de factor en menos grupos, tal vez debido a la escasez de datos en una de las categorías. También puede ocurrir cuando tiene diferentes ortografías o mayúsculas en los nombres de las categorías. Consideremos como ejemplo el factor

set.seed(1)
colorful <- sample(c("red", "Red", "RED", "blue", "Blue", "BLUE", "green", "gren"),
                   size = 20,
                   replace = TRUE)
colorful <- factor(colorful)

Dado que R es sensible a mayúsculas y minúsculas, una tabla de frecuencias de este vector aparecerá como se muestra a continuación.

table(colorful)
colorful  
blue  Blue  BLUE green  gren   red   Red   RED  
   3     1     4     2     4     1     3     2

Sin embargo, esta tabla no representa la distribución real de los datos, y las categorías pueden reducirse efectivamente a tres tipos: azul, verde y rojo. Se proporcionan tres ejemplos. El primero ilustra lo que parece una solución obvia, pero en realidad no proporcionará una solución. El segundo da una solución de trabajo, pero es detallado y computacionalmente costoso. La tercera no es una solución obvia, pero es relativamente compacta y computacionalmente eficiente.

Consolidando niveles usando factor ( factor_approach )

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

Tenga en cuenta que hay niveles duplicados. Todavía tenemos tres categorías para "Azul", que no completa nuestra tarea de consolidar los niveles. Además, existe una advertencia de que los niveles duplicados están en desuso, lo que significa que este código puede generar un error en el futuro.

La consolidación de niveles usando 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

Este código genera el resultado deseado, pero requiere el uso de sentencias ifelse anidadas. Si bien este enfoque no tiene nada de malo, la gestión de las declaraciones ifelse anidadas puede ser una tarea tediosa y debe hacerse con cuidado.

Consolidación de niveles de factores con una lista ( list_approach )

Una forma menos obvia de consolidar los niveles es usar una lista donde el nombre de cada elemento sea el nombre de la categoría deseada, y el elemento es un vector de caracteres de los niveles en el factor que debe asignarse a la categoría deseada. Esto tiene la ventaja adicional de trabajar directamente en el atributo de levels del factor, sin tener que asignar nuevos objetos.

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 de cada enfoque

El tiempo requerido para ejecutar cada uno de estos enfoques se resume a continuación. (En aras del espacio, no se muestra el código para generar este resumen)

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

El enfoque de lista se ejecuta aproximadamente el doble de rápido que el enfoque ifelse . Sin embargo, excepto en tiempos de cantidades muy grandes de datos, las diferencias en el tiempo de ejecución probablemente se medirán en microsegundos o milisegundos. Con tan pequeñas diferencias de tiempo, la eficiencia no necesita guiar la decisión de qué enfoque utilizar. En su lugar, utilice un enfoque que sea familiar y cómodo, y que usted y sus colaboradores comprendan en futuras revisiones.

Factores

Los factores son un método para representar variables categóricas en R. Dado un vector x cuyos valores se pueden convertir en caracteres usando as.character() , los argumentos predeterminados para factor() y as.factor() asignan un número entero a cada elemento distinto de El vector, así como un atributo de nivel y un atributo de etiqueta. Los niveles son los valores que x puede tomar y las etiquetas pueden ser el elemento dado o determinado por el usuario.

Para ejemplificar cómo funcionan los factores, crearemos un factor con atributos predeterminados, luego niveles personalizados y luego niveles y etiquetas personalizados.

# standard
factor(c(1,1,2,2,3,3))
[1] 1 1 2 2 3 3
Levels: 1 2 3

Pueden surgir instancias donde el usuario sabe que la cantidad de valores posibles que puede asumir un factor es mayor que los valores actuales en el vector. Para ello nos asignamos los niveles en 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

Por motivos de estilo, el usuario puede asignar etiquetas a cada nivel. Por defecto, las etiquetas son la representación de caracteres de los niveles. Aquí asignamos etiquetas para cada uno de los niveles posibles en el factor.

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

Normalmente, los factores solo se pueden comparar utilizando == y != Y si los factores tienen los mismos niveles. La siguiente comparación de factores falla a pesar de que parecen iguales porque los factores tienen diferentes niveles de factores.

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

Esto tiene sentido ya que los niveles adicionales en la RHS significan que R no tiene suficiente información sobre cada factor para compararlos de manera significativa.

Los operadores < , <= , > y >= solo se pueden usar para factores ordenados. Estos pueden representar valores categóricos que todavía tienen un orden lineal. Se puede crear un factor ordenado proporcionando el argumento ordered = TRUE a la función de factor o simplemente usando la función 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

Para más información, consulte la documentación de Factor .

Factores cambiantes y reordenadores.

Cuando los factores se crean con valores predeterminados, los levels se forman con un carácter as.character a las entradas y se ordenan alfabéticamente.

charvar <- rep(c("W", "n", "c"), times=c(17,20,14))
f <- factor(charvar)
levels(f)
# [1] "c" "n" "W"

En algunas situaciones, el tratamiento del orden predeterminado de los levels (orden alfabético / léxico) será aceptable. Por ejemplo, si un justs quiere plot las frecuencias, este será el resultado:

plot(f,col=1:length(levels(f)))

introduzca la descripción de la imagen aquí

Pero si queremos un orden de levels diferente, necesitamos especificar esto en los parámetros de levels o labels (cuidando que el significado de "orden" aquí sea diferente de los factores ordenados , vea más abajo). Hay muchas alternativas para lograr esa tarea dependiendo de la situación.

1. Redefinir el factor.

Cuando sea posible, podemos recrear el factor usando el parámetro de levels con el orden que queremos.

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"

Cuando los niveles de entrada son diferentes de los niveles de salida deseados, usamos el parámetro de labels que hace que el parámetro de levels se convierta en un "filtro" para valores de entrada aceptables, pero deja los valores finales de "niveles" para el vector factor como argumento para 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. Usa la función de relevel

Cuando hay un level específico que debe ser el primero, podemos usar el relevel . Esto sucede, por ejemplo, en el contexto del análisis estadístico, cuando una categoría base es necesaria para probar la hipótesis.

g<-relevel(f, "n") # moves n to be the first level
levels(g)
# [1] "n" "c" "W"  

Como se puede verificar f y g son los mismos.

all.equal(f, g)
# [1] "Attributes: < Component “levels”: 2 string mismatches >"
all.equal(f, g, check.attributes = F)
# [1] TRUE

3. Factores de reordenación.

Hay casos en los que necesitamos reorder los levels según un número, un resultado parcial, una estadística computada o cálculos previos. Vamos a reordenar en función de las frecuencias de los levels

table(g)
# g
#  n  c  W 
# 20 14 17 

La función de reorder es genérica (ver help(reorder) ), pero en este contexto necesita: x , en este caso el factor; X , un valor numérico de la misma longitud que x ; y FUN , una función que se aplicará a X y se computará por nivel de x , que determina el orden de los levels , aumentando por defecto. El resultado es el mismo factor con sus niveles reordenados.

g.ord <- reorder(g,rep(1,length(g)), FUN=sum) #increasing
levels(g.ord)
# [1] "c" "W" "n"

Para obtener un orden decreciente consideramos valores negativos ( -1 )

g.ord.d <- reorder(g,rep(-1,length(g)), FUN=sum)
levels(g.ord.d)
# [1] "n" "W" "c"

De nuevo el factor es el mismo que los demás.

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

Cuando hay una variable cuantitativa relacionada con la variable factor, podríamos usar otras funciones para reordenar los levels . Permite tomar los datos del iris ( help("iris") para obtener más información), para reordenar el factor de Species usando su promedio Sepal.Width .

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"

El boxplot habitual (por ejemplo, with(miris, boxplot(Petal.Width~Species) ) mostrará las especies en este orden: setosa , versicolor y virginica . Pero usando el factor ordenado obtenemos las especies ordenadas por su media 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) 

introduzca la descripción de la imagen aquí

Además, también es posible cambiar los nombres de los levels , combinarlos en grupos o agregar nuevos levels . Para eso utilizamos la función de los mismos levels nombre.

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 

- Factores ordenados.

Finalmente, sabemos que los factores ordered son diferentes de los factors , el primero se usa para representar datos ordinales y el segundo para trabajar con datos nominales . Al principio, no tiene sentido cambiar el orden de los levels para los factores ordenados, pero podemos cambiar sus 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

Factores de reconstrucción desde cero

Problema

Los factores se utilizan para representar variables que toman valores de un conjunto de categorías, conocidas como Niveles en R. Por ejemplo, algunos experimentos podrían caracterizarse por el nivel de energía de una batería, con cuatro niveles: vacío, bajo, normal y completo. Luego, para 5 sitios de muestreo diferentes, esos niveles podrían identificarse, en esos términos, de la siguiente manera:

lleno , lleno , normal , vacío , bajo

Normalmente, en bases de datos u otras fuentes de información, el manejo de estos datos se realiza mediante índices enteros arbitrarios asociados con las categorías o niveles. Si asumimos que, para el ejemplo dado, asignaríamos los índices de la siguiente manera: 1 = vacío, 2 = bajo, 3 = normal, 4 = completo, entonces las 5 muestras podrían codificarse como:

4 , 4 , 3 , 1 , 2

Puede suceder que, desde su fuente de información, por ejemplo, una base de datos, solo tenga la lista codificada de enteros y el catálogo que asocia cada entero con cada palabra clave de nivel. ¿Cómo se puede reconstruir un factor de R a partir de esa información?

Solución

Simularemos un vector de 20 enteros que representa las muestras, cada uno de los cuales puede tener uno de cuatro valores diferentes:

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

El primer paso es hacer un factor, a partir de la secuencia anterior, en el que los niveles o categorías son exactamente los números del 1 al 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
Niveles: 1 2 3 4

Ahora simplemente, debes vestir el factor ya creado con las etiquetas de índice:

levels(fii) <- c("empty", "low", "normal", "full")
fii

[1] normal completo vacío completo vacío normal bajo normal normal bajo vacío
[11] normal lleno vacío bajo lleno vacío vacío normal vacío completo vacío completo
Niveles: vacío bajo normal lleno



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow