2010-08-09 4 views
28

Sono stato sorpreso di vedere che R coarrà i fattori in un numero quando concatenando vettori. Questo succede anche quando i livelli sono gli stessi. Per esempio:Come concatenare i fattori, senza che vengano convertiti a livello intero?

> 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 

qual è il modo idiomatico di fare questo in R (nel mio caso questi vettori possono essere abbastanza grande)? Grazie.

risposta

27

Dal R Mailing list:

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

a fattori 'cbind', fare

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

Wow, non mi sono mai reso conto di averlo fatto. Qui è un work-around:

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

Con l'uscita:

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

Funzionerà solo se i due vettori hanno gli stessi livelli come qui.

+0

Great thanks ! Ho appena capito che unlist (lista (facs [1: 3], facs [4: 5])) funziona anche che è bello se non sai in anticipo che facs è un tipo di fattore. – Keith

+0

L'impostazione manuale dei livelli in questo modo non ha funzionato per il mio particolare problema. (Ho livelli a base 0. Potrei aver sottratto 1 e poi ricostruito il fattore, ma, ciò è fragile e nella parte inferiore dello spettro della scrutabalità, anche per R.) Invece (evviva?) Sono andato con 'unlist (lista (...)) '. –

8

Una soluzione alternativa è quella di convertire il fattore in un vettore di caratteri, quindi riconvertire quando si concatena la copia.

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

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

Si tratta di una R Gotcha davvero male. Lungo queste linee, eccone uno che ha ingoiato solo alcune ore del mio tempo.

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 

Mi sembra che la soluzione migliore sia quella di Richie, che costringe al personaggio.

> 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 

Fintanto che i livelli sono impostati correttamente, come Richie menziona.

0

Sulla base delle altre risposte, che utilizzano la conversione al personaggio che sto utilizzando la seguente funzione per concatenare fattori:

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

È possibile utilizzare questa funzione proprio come si usa c.

0

Ecco un altro modo per aggiungere a una variabile fattore quando l'installazione è leggermente diversa:

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

Per questo motivo preferisco lavorare con i fattori all'interno data.frames:

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

e sottoinsieme usa subset() o dplyr :: filter() ecc. piuttosto che gli indici di riga. Perché io non ho criteri sottoinsieme significativi in ​​questo caso, mi limiterò a usare la testa() e la coda():

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

Poi li si può manipolare facilmente, ad esempio:

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