2010-08-09 7 views
28

Me sorprendió ver que R forzará factores en un número al concatenar vectores. Esto sucede incluso cuando los niveles son los mismos. Por ejemplo:¿Cómo concatenar factores sin que se conviertan a un nivel entero?

> facs <- as.factor(c("i", "want", "to", "be", "a", "factor", "not", "an", "integer")) 
> facs 
[1] i  want to  be  a  factor not  an  integer 
Levels: a an be factor i integer not to want 
> c(facs[1 : 3], facs[4 : 5]) 
[1] 5 9 8 3 1 

cuál es la forma idiomática para hacer esto en R (en mi caso estos vectores pueden ser bastante grande)? Gracias.

Respuesta

27

Desde el R Mailing list:

unlist(list(facs[1 : 3], facs[4 : 5])) 

a factores '' cbind, hacer

data.frame(facs[1 : 3], facs[4 : 5]) 
6

Guau, nunca me di cuenta de eso. Aquí es una solución temporal:

x <- c(facs[1 : 3], facs[4 : 5]) 
x <- factor(x, levels=1:nlevels(facs), labels=levels(facs)) 
x 

Con la salida:

[1] i want to be a 
Levels: a an be factor i integer not to want 

Eso sólo será posible si los dos vectores tienen los mismos niveles que aquí.

+0

Grandes gracias ! Acabo de descubrir que la lista (lista (facs [1: 3], facs [4: 5])) también funciona, lo cual es bueno si no sabes de antemano que los facs son un tipo de factor. – Keith

+0

Establecer los niveles manualmente de esta manera no funcionó para mi problema en particular. (Tengo niveles basados ​​en 0. Pude haber restado 1 y luego reconstruido el factor, pero eso es frágil y en el extremo inferior del espectro de escrupulosidad, incluso para R.) En vez (¿hurra?), Fui con 'unlist (lista (...)) '. –

8

Una solución alternativa consiste en convertir el factor en un vector de caracteres, y luego volver a convertirlo cuando termine concatenando.

cfacs <- as.character(facs) 
x <- c(cfacs[1:3], cfacs[4:5]) 

# Now choose between 
factor(x) 
# and 
factor(x, levels = levels(facs)) 
4

Ésta es una muy mala Gotcha R. En ese sentido, aquí hay uno que simplemente tragó varias horas de mi tiempo.

x <- factor(c("Yes","Yes","No", "No", "Yes", "No")) 
y <- c("Yes", x) 

> y 
[1] "Yes" "2" "2" "1" "1" "2" "1" 
> is.factor(y) 
[1] FALSE 

Me parece que la mejor solución es Richie's, que coacciona al personaje.

> y <- c("Yes", as.character(x)) 
> y 
[1] "Yes" "Yes" "Yes" "No" "No" "Yes" "No" 
> y <- as.factor(y) 
> y 
[1] Yes Yes Yes No No Yes No 
Levels: No Yes 

Siempre que consigas los niveles establecidos correctamente, como menciona Richie.

0

Sobre la base de las otras respuestas que utilizan la conversión al personaje que estoy usando la siguiente función para concatenar factores:

concat.factor <- function(...){ 
    as.factor(do.call(c, lapply(list(...), as.character))) 
} 

Se puede usar esta función de la misma manera que utilizaría c.

0

Aquí es otra manera de añadir a una variable de factor cuando la configuración es ligeramente diferente:

facs <- factor(1:3, levels=1:9, 
       labels=c("i", "want", "to", "be", "a", "factor", "not", "an", "integer")) 
facs 
# [1] i  want to  be  a  factor not  an  integer 
# Levels: a an be factor i integer not to want 
facs[4:6] <- levels(facs)[4:6] 
facs 
# [1] i  want to  be  a  factor 
# Levels: i want to be a factor not an integer 
0

Por esta razón prefiero trabajar con factores dentro data.frames:

df <- data.frame(facs = as.factor(
     c("i", "want", "to", "be", "a", "factor", "not", "an", "integer"))) 

y subconjunto utilizando subset() o dplyr :: filter() etc. en lugar de índices de fila. Debido a que no tengo criterios de subconjuntos significativos en este caso, voy a usar la cabeza() y la cola():

df1 <- head(df, 4) 
df2 <- tail(df, 2) 

A continuación, se pueden manipular con facilidad, por ejemplo:

dfc <- rbind(df1, df2) 
dfc$facs 
#[1] i  want to  be  an  integer 
#Levels: a an be factor i integer not to want 
Cuestiones relacionadas