3.3 Factores
Los factores son un tipo de dato especial en R que permite almacenar de forma eficiente datos categoricos: nominales u ordinales. Estos se construyen, al igual que las matrices, a partir de vectores. Y asi como las matrices, los factores tienen un atributo que los diferencia de vectores ordinarios. Este atributo se refiere a los niveles (levels) del factor: los valores posibles de un factor. En el análisis de datos, es de vital importancia ya que el comportameinto de modelos estadisticos depende del tipo de los valores de entrada, además de que muchas funciones estadísticas en R tratan los factores de manera distinta a como se tratan los vectores de carcateres.
Para crear un factor se usa la función factor
:
rating <- c("Very Bad", "Medium", "Very Bad", "Good", "Medium", "Very Good", "Medium", "Good", "Medium", "Bad")
rating_factor <- factor(rating)
rating_factor
## [1] Very Bad Medium Very Bad Good Medium Very Good Medium
## [8] Good Medium Bad
## Levels: Bad Good Medium Very Bad Very Good
El resultado muestra los elementos del factor, y debajo, las etiquetas de los niveles del factor. Podemos ver que este es distinto de un vector de caracteres:
## [1] "integer"
El tipo de los elementos almacenados en el vector es integer
. Esto es asi porque los factores se representan como enteros internamente. Los niveles son etiquetas asociadas a cada uno de esos enteros.
Se puede saber los niveles de un factor usando la función levels
:
## [1] "Bad" "Good" "Medium" "Very Bad" "Very Good"
la cual devuelve un vector de caracteres con las etiquetas de los niveles, en orden alfabético. Esto ocurre así por omisión: los niveles de un factor se almacenan en orden alfabético. Sin embargo, podemos especificar el orden en el que se almacenan las etiquetas al crear el factor:
rating_factor <- factor(rating, levels=c("Very Bad", "Bad", "Medium", "Good", "Very Good"))
rating_factor
## [1] Very Bad Medium Very Bad Good Medium Very Good Medium
## [8] Good Medium Bad
## Levels: Very Bad Bad Medium Good Very Good
Esto es importante cuando se quiere especificar un nivel de referencia con el cual comparar los resultados de un modelo estadistico. Por ejemplo, si en un estudio se busca usar como variable independiente el habito de fumar, codificado como Fumador y No Fumador, tiene sentido usar el nivel de No Fumador como referencia, de forma que cualquier analisis que use un modelo estadistico compare el cambio en la respuesta como consecuencia del habito de fuumar. Sin embargo, al crear un factor, debido a que se almacenan alfabéticamente los niveles, el nivel Fumador quedaría como nivel de referencia:
smoker <- c("No Fumador", "Fumador", "No Fumador", "No Fumador", "Fumador", "Fumador", "No Fumador", "Fumador", "Fumador", "No Fumador")
smoker_factor <- factor(smoker)
smoker_factor
## [1] No Fumador Fumador No Fumador No Fumador Fumador Fumador
## [7] No Fumador Fumador Fumador No Fumador
## Levels: Fumador No Fumador
Es por ello, que resulta conveniente el uso del argumento levels
en la función factor
:
smoker <- c("No Fumador", "Fumador", "No Fumador", "No Fumador", "Fumador", "Fumador", "No Fumador", "Fumador", "Fumador", "No Fumador")
smoker_factor <- factor(smoker, levels=c("No Fumador", "Fumador"))
smoker_factor
## [1] No Fumador Fumador No Fumador No Fumador Fumador Fumador
## [7] No Fumador Fumador Fumador No Fumador
## Levels: No Fumador Fumador
Hasta este momento, hemos asumido que los factores que hemos creado corresponden a representaciones de variables catgoricas nominales.
Para crear factores que correspondan a representaciones de variables catgoricas ordinales, se puede hacer especificando el argumento ordered=TRUE
en la funcion factor
; o se puede hacer directamente usando la función ordered
:
# Este ordenamiento tiene sentido en escalas tipo Likert
rating_factor <- factor(rating, levels=c("Very Bad", "Bad", "Medium", "Good", "Very Good"), ordered=TRUE)
rating_factor <- ordered(rating, levels=c("Very Bad", "Bad", "Medium", "Good", "Very Good"))
El especificar de forma explicita los niveles tiene otra ventaja importante: Permite detectar tempranamente errores de codificación de elementos dentro de una variable.
Por ejemplo, digamos que al definir el vector smoker
cometimos un error de tipeo, y uno de los elementos lo escribimos "Funador"
(tecleamos N en lugar de M). Al crear el factor con los niveles especificados:
smoker <- c("No Fumador", "Funador", "No Fumador", "No Fumador", "Fumador", "Fumador", "No Fumador", "Fumador", "Fumador", "No Fumador") # El segundo elemento tiene el error de tipeo
smoker_factor <- factor(smoker, levels=c("No Fumador", "Fumador"))
smoker_factor
## [1] No Fumador <NA> No Fumador No Fumador Fumador Fumador
## [7] No Fumador Fumador Fumador No Fumador
## Levels: No Fumador Fumador
vemos como el factor contiene un NA
donde ocurrió el error de tipeo.
Esto es un problema, ya que pueden introducirse de forma inesperada datos faltantes donde no los hay, y, peor aún, R no nos advierte de nada de esto.
Es posible evitar este comportamiento usando parse_factor
en el paquete readr
(que usaremos mas adelante para importar datos). Ahora, al crear el factor, R nos muestra una advertencia de que algo no salió como se esperaba, haciendonos sospechar del resultado y que seamos cuidadosos.
library(readr)
smoker_factor <- parse_factor(smoker, levels=c("No Fumador", "Fumador")) # Genera una advertencia
## Warning: 1 parsing failure.
## row col expected actual
## 2 -- value in level set Funador
## [1] No Fumador <NA> No Fumador No Fumador Fumador Fumador
## [7] No Fumador Fumador Fumador No Fumador
## attr(,"problems")
## # A tibble: 1 × 4
## row col expected actual
## <int> <int> <chr> <chr>
## 1 2 NA value in level set Funador
## Levels: No Fumador Fumador
Buenas prácticas de programación. De forma general, al crear factores, siempre es mejor hacer explicitos los niveles y, aunque las advertencias son adecuadas para manjar con cuidado resultados inesperados como los del ejemplo anterior, siempre es preferible no crear factores que de entrada sabemos son erroneos.
Para evitar la creación de factores mal especificados, se utiliza la función fct
en el paquete forcats
(un paquete diseñado especificamente para trabajar con factores), el cual se diferencia de factor
en que los niveles se crean en el orden en que aparecen en el vector de entrada, y no alfabéticamente.
library(forcats)
smoker <- c("No Fumador", "Fumador", "No Fumador", "No Fumador", "Fumador", "Fumador", "No Fumador", "Fumador", "Fumador", "No Fumador")
smoker_factor <- fct(smoker, levels=c("No Fumador", "Fumador"))
Crear factores ordenados no es tan directo, pero el beneficio de crear factores correctos desde el inicio es más importante:
# Especificando los niveles
rating_factor <- fct(rating, levels=c("Very Bad", "Bad", "Medium", "Good", "Very Good")) %>%
lvls_reorder(1:5, ordered=TRUE)
El simbolo %>%
es un operador, el operador de tuberia (de la palabra inglesa pipe), el cual se carga en la sesión de R al cargar el paquete forcats
. El uso de este operador se difiere hasta el siguiente capitulo.
En este momento es suficiente que entienda que cada vez que aparezca una expresión de la forma objeto %>% funcion(primer_arg, segundo_arg, ...)
, R lo interpreta como funcion(objeto, primer_arg, segundo_arg, ...)
.
Otras funciones importantes para manejar factores, junto con un ejemplo de su uso, se presenta a continuación20:
fct_relevel
: nos permite jugar con el orden de los niveles de un factor. Por ejemplo:
fct_inorder
,fct_infreq
: estas se encargan de ordenar los niveles de un factor en el orden en el que aparecen (fct_inorder
) o en el orden especificado por la frecuencia con que aprece cada etiqieta (fct_infreq
).
vertebrates <- fct(sample(c("Mamifero", "Ave", "Reptil", "Pez", "Anfibio"), 250, replace=TRUE))
invertebrate <- fct(sample(c("Diptero", "Odonata", "Porifera", "Cnidario", "Aracnido"), 25, replace=TRUE))
animal_cat <- fct_c(vertebrates, invertebrate) # fct_c permite combinar factores, preservando los niveles de los factores de entrada
animal_cat %>% fct_infreq()
fct_lump
yfct_lump_*
: estas funciones permiten agrupar niveles, preservando un numero especificado de veeces o solo aquellos niveles de baja frecuencia.
fct_expand
: permite añadir niveles adicionales a un factor, ya sea que existan o no representastes de estos niveles en el factor.
fct_collapse
: permite agrupar los niveles en niveles nuevos manualmente definidos.
animal_cat %>%
fct_collapse(
Vertebrados=c("Mamifero", "Ave", "Reptil", "Pez", "Anfibio"),
Invertebrados=c("Diptero", "Odonata", "Porifera", "Cnidario", "Aracnido"))
fct_drop
: devuelve un factor cuyos niveles son solo aquellos representados dentro del factor.
fct_other
: Reemplaza los niveles especificados con un nivel especificado (por omisión, “other”).
animal_cat %>%
fct_expand("Himenoptero", "Platelmintos", "Equinodermos", "Anfioxo", after=5) %>%
fct_other(keep = c("Mamifero", "Ave", "Reptil", "Pez", "Anfibio", "Anfioxo"),
other_level="Sin notocordio") # Deja los cordados
fct_count
: cuenta el numero de elmentos del factor que pertenece a cada nivel. El resultadoe s una estructura de datos especial llamadatibble
que veremos en la siguiente sección.
Más información esta disponible en la documentación.↩︎