variable uso transformar recodificar numericas numerica funcion factor estadistica convertir categoricas r language-design internals r-factor

uso - transformar variables en r



Factores en R: ¿más que una molestia? (7)

Uno de los tipos de datos básicos en R es factores. En mi experiencia, los factores son básicamente un dolor y nunca los uso. Siempre me convierto en personajes. Me siento extrañamente como si me estuviera perdiendo algo.

¿Hay algunos ejemplos importantes de funciones que usan factores como variables de agrupación donde el tipo de datos de factores se vuelve necesario? ¿Hay circunstancias específicas en las que debería usar factores?


¡Qué título tan sarcástico!

Creo que muchas funciones de estimación le permiten usar factores para definir fácilmente las variables ficticias ... pero no las uso para eso.

Los uso cuando tengo vectores de caracteres muy grandes con pocas observaciones únicas. Esto puede reducir el consumo de memoria, especialmente si las cadenas en el vector de caracteres son más largas.

PD: estoy bromeando sobre el título. Vi tu tweet. ;-)


Los factores ordenados son asombrosos, si me encantan las naranjas y odio las manzanas, pero no me importan las uvas, no necesito administrar un índice extraño para decirlo:

d <- data.frame(x = rnorm(20), f = sample(c("apples", "oranges", "grapes"), 20, replace = TRUE, prob = c(0.5, 0.25, 0.25))) d$f <- ordered(d$f, c("apples", "grapes", "oranges")) d[d$f >= "grapes", ]


Los factores son fantásticos cuando uno hace un análisis estadístico y realmente explora los datos. Sin embargo, antes de eso, cuando uno lee, limpia, soluciona problemas, se fusiona y generalmente manipula los datos, los factores son un dolor total. Más recientemente, como en los últimos años, muchas de las funciones han mejorado para manejar mejor los factores. Por ejemplo, rbind juega muy bien con ellos. Todavía me parece una molestia total haber quedado en niveles vacíos después de una función de subconjunto.

#drop a whole bunch of unused levels from a whole bunch of columns that are factors using gdata require(gdata) drop.levels(dataframe)

Sé que es fácil recodificar los niveles de un factor y cambiar las etiquetas y también hay maneras maravillosas de reordenar los niveles. Mi cerebro simplemente no puede recordarlos y tengo que volver a aprenderlo cada vez que lo uso. Recodificar debería ser mucho más fácil de lo que es.

Las funciones de cadena de R son bastante fáciles y lógicas de usar. Entonces, cuando manipulo, generalmente prefiero los personajes a los factores.


Los factores son un excelente motor de identificación de "casos únicos". He recreado esto muchas veces, y a pesar de algunas arrugas ocasionalmente, son extremadamente poderosas.

library(dplyr) d <- tibble(x = sample(letters[1:10], 20, replace = TRUE)) ## normalize this table into an indexed value across two tables id <- tibble(x_u = sort(unique(d$x))) %>% mutate(x_i = row_number()) di <- tibble(x_i = as.integer(factor(d$x))) ## reconstruct d$x when needed d2 <- inner_join(di, id) %>% transmute(x = x_u) identical(d, d2) ## [1] TRUE

Si hay una mejor manera de hacer esta tarea, me gustaría verla, no veo discutida esta capacidad de factor .


Un factor es más análogo a un tipo enumerado en otros idiomas. Su uso apropiado es para una variable que solo puede asumir uno de los conjuntos de valores prescritos. En estos casos, no todos los posibles valores permitidos pueden estar presentes en un conjunto particular de datos y los niveles "vacíos" reflejan con precisión eso.

Considera algunos ejemplos. Para algunos datos que se recopilaron en todos los Estados Unidos, el estado debe registrarse como un factor. En este caso, el hecho de que no se recolectaron casos de un estado en particular es relevante. Podría haber habido datos de ese estado, pero sucedió (por alguna razón, que puede ser una razón de interés) para no serlo. Si se recolectara la ciudad natal, no sería un factor. No hay un conjunto preestablecido de posibles ciudades natales. Si los datos se obtuvieron de tres ciudades en lugar de nacional, la ciudad sería un factor: hay tres opciones que se dieron desde el principio y si no se encontraron casos / datos relevantes en una de esas tres ciudades, eso es relevante.

Otros aspectos de los factor , como proporcionar una forma de dar un orden arbitrario a un conjunto de cadenas, son características secundarias útiles del factor s, pero no son la razón de su existencia.


tapply (y agregado ) se basan en factores. La relación información-esfuerzo de estas funciones es muy alta.

Por ejemplo, en una sola línea de código (la llamada a tapply a continuación) puede obtener el precio promedio de los diamantes por Corte y Color:

> data(diamonds, package="ggplot2") > head(dm) Carat Cut Clarity Price Color 1 0.23 Ideal SI2 326 E 2 0.21 Premium SI1 326 E 3 0.23 Good VS1 327 E > tx = with(diamonds, tapply(X=Price, INDEX=list(Cut=Cut, Color=Color), FUN=mean)) > a = sort(1:diamonds(tx)[2], decreasing=T) # reverse columns for readability > tx[,a] Color Cut J I H G F E D Fair 4976 4685 5136 4239 3827 3682 4291 Good 4574 5079 4276 4123 3496 3424 3405 Very Good 5104 5256 4535 3873 3779 3215 3470 Premium 6295 5946 5217 4501 4325 3539 3631 Ideal 4918 4452 3889 3721 3375 2598 2629


Debes usar factores. Sí, pueden ser un problema, pero mi teoría es que el 90% de por qué son un dolor es porque en read.table y read.csv , el argumento stringsAsFactors = TRUE de forma predeterminada (y la mayoría de los usuarios pierden esta sutileza). Digo que son útiles porque los paquetes de adaptación de modelos como lme4 usan factores y factores ordenados para adaptarse diferencialmente a los modelos y determinar el tipo de contrastes a usar. Y los paquetes gráficos también los usan para agruparlos. ggplot y la mayoría de las funciones de ajuste de modelos ggplot a los vectores de caracteres a factores, por lo que el resultado es el mismo. Sin embargo, terminas con advertencias en tu código:

lm(Petal.Length ~ -1 + Species, data=iris) # Call: # lm(formula = Petal.Length ~ -1 + Species, data = iris) # Coefficients: # Speciessetosa Speciesversicolor Speciesvirginica # 1.462 4.260 5.552 iris.alt <- iris iris.alt$Species <- as.character(iris.alt$Species) lm(Petal.Length ~ -1 + Species, data=iris.alt) # Call: # lm(formula = Petal.Length ~ -1 + Species, data = iris.alt) # Coefficients: # Speciessetosa Speciesversicolor Speciesvirginica # 1.462 4.260 5.552

Mensaje de advertencia: en model.matrix.default(mt, mf, contrasts) :

variable Species convertida a un factor

Una cosa complicada es todo el drop=TRUE bit. En vectores, esto funciona bien para eliminar niveles de factores que no están en los datos. Por ejemplo:

s <- iris$Species s[s == ''setosa'', drop=TRUE] # [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # Levels: setosa s[s == ''setosa'', drop=FALSE] # [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # Levels: setosa versicolor virginica

Sin embargo , con data.frame s, el comportamiento de [.data.frame() es diferente: vea este correo electrónico o ?"[.data.frame" . Usar drop=TRUE en data.frame s no funciona como se imaginaría:

x <- subset(iris, Species == ''setosa'', drop=TRUE) # susbetting with [ behaves the same way x$Species # [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa # Levels: setosa versicolor virginica

Afortunadamente, puede eliminar los factores fácilmente con droplevels() para soltar los niveles de factor no utilizados para un factor individual o para cada factor en un data.frame (desde R 2.12):

x <- subset(iris, Species == ''setosa'') levels(x$Species) # [1] "setosa" "versicolor" "virginica" x <- droplevels(x) levels(x$Species) # [1] "setosa"

Esta es la forma de mantener los niveles que seleccionaste para que no ggplot en ggplot leyendas de ggplot .

Internamente, los factor son enteros con un vector de caracteres de nivel de atributo (ver attributes(iris$Species) y class(attributes(iris$Species)$levels) ), que está limpio. Si tuviera que cambiar un nombre de nivel (y estaba usando cadenas de caracteres), esta sería una operación mucho menos eficiente. Y cambio mucho los nombres de nivel, especialmente para ggplot leyendas de ggplot . Si falsifica factores con vectores de caracteres, existe el riesgo de que cambie solo un elemento y accidentalmente cree un nuevo nivel separado.