Qué es realmente un factor
Un factor es la respuesta de R a los datos categóricos - valores que vienen de un menú fijo de posibilidades: grupos de tratamiento, respuestas de encuesta, tallas de camiseta. Al imprimirse parece un vector de caracteres, pero no lo es. Por dentro, un factor es un vector de códigos enteros más una tabla de consulta de etiquetas llamadas niveles:
La impresión muestra las etiquetas y luego una línea Levels: con el menú. as.integer() deja al descubierto la maquinaria: los códigos vuelven como 3 1 3 2, porque cada valor es en realidad un índice en la tabla de niveles - y los niveles se ordenan alfabéticamente por defecto (large, medium, small), no en el orden en que llegaron los datos. Así que small es el código 3 y large el 1, lo que no es la intuición de nadie. Recuerda este orden alfabético por defecto; provoca dos de las trampas de más abajo.
¿Por qué molestarse con este diseño de dos capas en lugar de cadenas normales? Porque la estadística lo necesita. Un modelo no puede multiplicar "small" por un coeficiente - pero sí puede codificar tres niveles conocidos en columnas de 0 y 1. Funciones como lm(), glm(), table() y la maquinaria detrás del ANOVA se apoyan en los factores para saber que una variable es categórica, cuál es el conjunto completo de categorías (incluidas las ausentes de los datos) y cuál es la categoría base. Los vectores de caracteres normales no llevan nada de eso.
Crear factores: levels, labels y table()
Por defecto, factor() toma los valores distintos que encuentra y los ordena alfabéticamente en niveles. A menudo querrás controlar tanto el conjunto como el orden - pasa levels =:
Ahora los niveles van en su orden natural de tamaño, y table() - el recuento de frecuencias de una línea que usarás constantemente con factores - informa de los conteos en ese orden también. nlevels() cuenta las categorías.
levels = te da dos cosas más. Los valores de los datos que no estén en tu lista de niveles se convierten en NA (bueno: las erratas salen a la luz en vez de convertirse en su propia categoría). Y los niveles con cero apariciones siguen existiendo, así que un resumen de respuestas de encuesta muestra "totalmente en desacuerdo: 0" en lugar de fingir que la opción nunca existió.
labels = renombra los niveles en el momento de la creación, lo que resulta útil cuando los datos en bruto usan códigos:
Y as.factor(x) es el conversor rápido para un vector existente cuando los valores por defecto sirven.
Factores ordenados para datos ordinales
Los factores normales tratan las categorías como no ordenadas - "rojo" no es menor que "azul". Pero algunas escalas categóricas tienen una jerarquía genuina: bajo/medio/alto, en desacuerdo/neutral/de acuerdo. Decláralo con ordered = TRUE:
La impresión ahora muestra Levels: low < medium < high, y los operadores de comparación funcionan: puedes preguntar si una valoración supera a otra o filtrar todo lo que esté en "medium" o por encima - ambas cosas dan error (bueno, avisos y NA) con un factor no ordenado. Los factores ordenados también cambian cómo codifican los modelos la variable (contrastes polinómicos en lugar de variables ficticias), que suele ser lo que quieres para predictores ordinales.
Usa ordered = TRUE solo cuando la jerarquía sea real. Codificar grupos corrientes como ordenados cambia la salida de los modelos de formas fáciles de malinterpretar.
El nivel de referencia y relevel()
El primer nivel de un factor es especial: las funciones de modelado lo tratan como la categoría de referencia, la base con la que se mide el coeficiente de todos los demás niveles. Como el orden de niveles por defecto es alfabético, tu base la elige el alfabeto salvo que intervengas - y que "control" pierda contra "aspirin" alfabéticamente no es una decisión científica.
relevel() asciende un nivel al primer puesto:
Antes: control resulta ser el primero solo por suerte alfabética. Después de relevel(..., ref = "control") es el primero a propósito. En una regresión lineal con este predictor, el coeficiente de treatment ahora responde a "¿en qué se diferencia el tratamiento del control?" - la pregunta que de verdad hiciste. Siempre que los coeficientes categóricos de un modelo parezcan confusos, comprueba primero el nivel de referencia.
(Para una reordenación completa - no solo el primer puesto - vuelve a pasar un vector levels = completo a factor().)
La trampa clásica: convertir un factor a numérico
A veces los números llegan como factores - normalmente una columna de un CSV que contenía algún valor no numérico despistado. Convertirlos de vuelta parece obvio y sale memorablemente mal:
as.numeric(f) devuelve 2 1 3. No 20, 10, 30 - los códigos de nivel. Los niveles se ordenan alfabéticamente como "10", "20", "30", así que "20" es el nivel 2 y se convierte en... 2. Sin error, sin aviso, con enteros pequeños de aspecto plausible sustituyendo discretamente tus datos. Se han retractado análisis por esto.
La ruta correcta pasa por carácter: as.numeric(as.character(f)) recupera primero las etiquetas como texto y luego interpreta el texto como números - 20 10 30. Grábate este modismo: de factor a numérico siempre se pasa por as.character().
droplevels() y la historia de stringsAsFactors
Hacer un subconjunto de un factor conserva el conjunto completo de niveles, incluso los de categorías que ya no aparecen:
Después de filtrar large, table() sigue informando de él - con un recuento de 0. A veces eso es exactamente lo correcto (quieres que la categoría vacía se vea). Cuando no lo es - los grupos con recuento cero ensucian los gráficos y pueden romper los análisis estratificados -, droplevels() descarta los niveles sin observaciones.
Una nota histórica que necesitarás al leer código antiguo o respuestas de Stack Overflow: antes de R 4.0 (2020), data.frame() y read.csv() convertían automáticamente cada columna de caracteres en un factor - stringsAsFactors = TRUE era el valor por defecto. Una década de tutoriales está plagada de soluciones improvisadas para factores que nadie pidió. Desde R 4.0 el valor por defecto es FALSE: las cadenas siguen siendo cadenas y creas los factores deliberadamente, donde una variable de tu data frame sea genuinamente categórica. Ese es el hábito correcto - factores explícitos, a propósito, con los niveles que tú elegiste.
Lo que te llevas
- Un factor = códigos enteros + etiquetas de nivel; es lo que le dice a las funciones estadísticas que una variable es categórica.
- Controla el conjunto y el orden de categorías con
levels =, renómbralas conlabels =, cuéntalas contable(). ordered = TRUEhabilita las comparaciones para escalas genuinamente ordinales.- El primer nivel es la base del modelo - fíjalo deliberadamente con
relevel(f, ref = ...). - Nunca hagas
as.numeric(f)directamente - siempreas.numeric(as.character(f)). droplevels()limpia los niveles no usados tras hacer un subconjunto; desde R 4.0, las cadenas siguen siendo cadenas salvo que crees factores tú mismo.
Lo siguiente: los data frames - donde factores, números y texto conviven como columnas de una misma tabla.
Preguntas frecuentes
¿Qué es un factor en R?
Un factor es el tipo de R para los datos categóricos - valores tomados de un conjunto fijo de posibilidades llamadas niveles. Por dentro es un vector de códigos enteros más una tabla de etiquetas de nivel, que es lo que permite a las funciones estadísticas tratar correctamente las categorías (contarlas, codificarlas como variables ficticias en los modelos) en lugar de tratarlas como texto libre.
¿Cómo se convierte un factor a numérico en R?
Pasando por carácter: as.numeric(as.character(f)). Llamar directamente a as.numeric(f) devuelve los códigos internos de nivel (1, 2, 3, ...), no los valores que muestran las etiquetas - así que un factor que muestra "20" puede volver como 2. Este es uno de los bugs silenciosos más comunes de R.
¿Qué hace relevel() en R?
Mueve un nivel elegido a la primera posición: relevel(group, ref = "control"). El primer nivel es la categoría de referencia (la base) con la que las funciones de modelado como lm() y glm() comparan todos los demás niveles, así que elegirla deliberadamente hace que los coeficientes de la regresión signifiquen lo que pretendes.
¿Por qué mi factor sigue mostrando niveles que eliminé?
Hacer un subconjunto de un factor conserva el conjunto completo de niveles aunque algunos ya no aparezcan, así que table() muestra categorías con recuento cero y los modelos siguen reservándoles espacio. Ejecuta droplevels() sobre el subconjunto para descartar los niveles no usados.