R Language
Factores
Buscar..
Sintaxis
- factor (x = carácter (), niveles, etiquetas = niveles, excluir = NA, ordenado = ordenado (x), nmax = NA)
- 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.
- Se almacena internamente como un vector
integer
. - Mantiene un atributo de
levels
muestra la representación de caracteres de los valores. - 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
- El aumento de datos de caracteres no estructurados y / o poco controlados.
- 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)))
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)
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