questions - r studiodio
Limpiar los niveles de factor(colapsando múltiples niveles/etiquetas) (7)
Como la pregunta se titula Limpieza de los niveles de los factores (colapso de múltiples niveles / etiquetas) , el paquete de los forcats
debe mencionarse aquí, en aras de la exhaustividad. forcats
aparecieron en CRAN en agosto de 2016.
Hay varias funciones de conveniencia disponibles para limpiar niveles de factor:
x <- c("Y", "Y", "Yes", "N", "No", "H")
library(forcats)
Contraer los niveles de factor en grupos definidos manualmente
fct_collapse(x, Yes = c("Y", "Yes"), No = c("N", "No"), NULL = "H")
#[1] Yes Yes Yes No No <NA>
#Levels: No Yes
Cambiar los niveles de factor a mano
fct_recode(x, Yes = "Y", Yes = "Yes", No = "N", No = "No", NULL = "H")
#[1] Yes Yes Yes No No <NA>
#Levels: No Yes
Reetiquetar automáticamente los niveles de factor, colapsar según sea necesario
fun <- function(z) {
z[z == "Y"] <- "Yes"
z[z == "N"] <- "No"
z[!(z %in% c("Yes", "No"))] <- NA
z
}
fct_relabel(factor(x), fun)
#[1] Yes Yes Yes No No <NA>
#Levels: No Yes
Tenga en cuenta que fct_relabel()
funciona con niveles de factor, por lo que espera un factor como primer argumento. Las otras dos funciones, fct_collapse()
y fct_recode()
, también aceptan un vector de caracteres que es una característica no documentada.
Reordenar los niveles de factor por primera aparición
El resultado esperado dado por el OP es
[1] Yes Yes Yes No No <NA>
Levels: Yes No
Aquí los niveles se ordenan tal como aparecen en x
que es diferente del valor predeterminado ( ?factor
?: Los niveles de un factor se clasifican por defecto ).
Para estar en línea con el resultado esperado, esto se puede lograr utilizando fct_inorder()
antes de colapsar los niveles:
fct_collapse(fct_inorder(x), Yes = c("Y", "Yes"), No = c("N", "No"), NULL = "H")
fct_recode(fct_inorder(x), Yes = "Y", Yes = "Yes", No = "N", No = "No", NULL = "H")
Ambos devuelven el resultado esperado con niveles en el mismo orden, ahora.
¿Cuál es la forma más efectiva (es decir, eficiente / apropiada) de limpiar un factor que contiene múltiples niveles que deben colapsarse? Es decir, cómo combinar dos o más niveles de factores en uno.
Aquí hay un ejemplo donde los dos niveles "Sí" e "Y" deben colapsarse a "Sí", y "No" y "N" colapsados a "No":
## Given:
x <- c("Y", "Y", "Yes", "N", "No", "H") # The ''H'' should be treated as NA
## expectedOutput
[1] Yes Yes Yes No No <NA>
Levels: Yes No # <~~ NOTICE ONLY **TWO** LEVELS
Una opción es, por supuesto, limpiar las cuerdas antes de la mano usando sub
y amigos.
Otro método es permitir etiquetas duplicadas y luego colocarlas
## Duplicate levels ==> "Warning: deprecated"
x.f <- factor(x, levels=c("Y", "Yes", "No", "N"), labels=c("Yes", "Yes", "No", "No"))
## the above line can be wrapped in either of the next two lines
factor(x.f)
droplevels(x.f)
Sin embargo, ¿hay una manera más efectiva ?
Si bien sé que los argumentos de levels
y labels
deben ser vectores, experimenté con listas y listas de nombres y vectores nombrados para ver qué sucede. De más está decir que ninguno de los siguientes me acercó más a mi objetivo.
factor(x, levels=list(c("Yes", "Y"), c("No", "N")), labels=c("Yes", "No"))
factor(x, levels=c("Yes", "No"), labels=list(c("Yes", "Y"), c("No", "N")))
factor(x, levels=c("Y", "Yes", "No", "N"), labels=c(Y="Yes", Yes="Yes", No="No", N="No"))
factor(x, levels=c("Y", "Yes", "No", "N"), labels=c(Yes="Y", Yes="Yes", No="No", No="N"))
factor(x, levels=c("Yes", "No"), labels=c(Y="Yes", Yes="Yes", No="No", N="No"))
No sé cuál es tu caso de uso real, pero ¿qué strtrim
tendría strtrim
aquí?
factor( strtrim( x , 1 ) , levels = c("Y" , "N" ) , labels = c("Yes" , "No" ) )
#[1] Yes Yes Yes No No <NA>
#Levels: Yes No
Otra forma es hacer una tabla que contenga el mapeo:
# stacking the list from Aaron''s answer
fmap = stack(list(Yes = c("Y", "Yes"), No = c("N", "No")))
fmap$ind[ match(x, fmap$values) ]
# [1] Yes Yes Yes No No <NA>
# Levels: No Yes
# or...
library(data.table)
setDT(fmap)[x, on=.(values), ind ]
# [1] Yes Yes Yes No No <NA>
# Levels: No Yes
Prefiero esta forma, ya que deja un objeto fácilmente inspeccionable que resume el mapa; y el código data.table se parece a cualquier otra unión en esa sintaxis.
Por supuesto, si no desea que un objeto como fmap
resuma el cambio, puede ser un "trazador de líneas":
library(data.table)
setDT(stack(list(Yes = c("Y", "Yes"), No = c("N", "No"))))[x, on=.(values), ind ]
# [1] Yes Yes Yes No No <NA>
# Levels: No Yes
Puede usar la función siguiente para combinar / contraer múltiples factores:
combofactor <- function(pattern_vector,
replacement_vector,
data) {
levels <- levels(data)
for (i in 1:length(pattern_vector))
levels[which(pattern_vector[i] == levels)] <-
replacement_vector[i]
levels(data) <- levels
data
}
Ejemplo:
Inicializar x
x <- factor(c(rep("Y",20),rep("N",20),rep("y",20),
rep("yes",20),rep("Yes",20),rep("No",20)))
Verifica la estructura
str(x)
# Factor w/ 6 levels "N","No","y","Y",..: 4 4 4 4 4 4 4 4 4 4 ...
Usa la función:
x_new <- combofactor(c("Y","N","y","yes"),c("Yes","No","Yes","Yes"),x)
Vuelva a verificar la estructura:
str(x_new)
# Factor w/ 2 levels "No","Yes": 2 2 2 2 2 2 2 2 2 2 ...
Similar al enfoque de @ Aaron, pero un poco más simple sería:
x <- c("Y", "Y", "Yes", "N", "No", "H")
x <- factor(x)
# levels(x)
# [1] "H" "N" "No" "Y" "Yes"
# NB: the offending levels are 1, 2, & 4
levels(x)[c(1,2,4)] <- c(NA, "No", "Yes")
x
# [1] Yes Yes Yes No No <NA>
# Levels: No Yes
Tal vez un vector con nombre como clave pueda ser de utilidad:
> factor(unname(c(Y = "Yes", Yes = "Yes", N = "No", No = "No", H = NA)[x]))
[1] Yes Yes Yes No No <NA>
Levels: No Yes
Esto se ve muy similar a tu último intento ... pero este funciona :-)
Utilice la función de levels
y páselo por una lista con nombre, siendo los nombres los nombres deseados de los niveles y los elementos los nombres actuales que deben renombrarse.
x <- c("Y", "Y", "Yes", "N", "No", "H")
x <- factor(x)
levels(x) <- list(Yes=c("Y", "Yes"), No=c("N", "No"))
x
## [1] Yes Yes Yes No No <NA>
## Levels: Yes No
Como se menciona en la documentación de levels
; también vea los ejemplos allí.
valor: para el método ''factor'', un vector de cadenas de caracteres con una longitud de al menos el número de niveles de ''x'', o una lista con nombre que especifica cómo cambiar el nombre de los niveles.
Esto también se puede hacer en una línea, como lo hace Marek aquí: https://.com/a/10432263/210673 ; los levels<-
hechicería se explican aquí https://.com/a/10491881/210673 .
> `levels<-`(factor(x), list(Yes=c("Y", "Yes"), No=c("N", "No")))
[1] Yes Yes Yes No No <NA>
Levels: Yes No