2013-12-17 13 views
36

Dato un frame di dati (preesistente) con colonne di vari tipi, qual è il modo più semplice per convertire tutte le colonne di caratteri in fattori, senza influire su colonne di altri tipi?Converti tutte le colonne di caratteri del frame di dati in fattori

Ecco un esempio data.frame:

df <- data.frame(A = factor(LETTERS[1:5]), 
       B = 1:5, C = as.logical(c(1, 1, 0, 0, 1)), 
       D = letters[1:5], 
       E = paste(LETTERS[1:5], letters[1:5]), 
       stringsAsFactors = FALSE) 
df 
# A B  C D E 
# 1 A 1 TRUE a A a 
# 2 B 2 TRUE b B b 
# 3 C 3 FALSE c C c 
# 4 D 4 FALSE d D d 
# 5 E 5 TRUE e E e 
str(df) 
# 'data.frame': 5 obs. of 5 variables: 
# $ A: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5 
# $ B: int 1 2 3 4 5 
# $ C: logi TRUE TRUE FALSE FALSE TRUE 
# $ D: chr "a" "b" "c" "d" ... 
# $ E: chr "A a" "B b" "C c" "D d" ... 

so che posso fare:

df$D <- as.factor(df$D) 
df$E <- as.factor(df$E) 

C'è un modo per automatizzare questo processo un po 'di più?

+0

@AnandaMahto Grazie. Di solito sto cercando di evitare la conversione in fattori e sono spesso costretto a impostare l'opzione globale. Quindi, l'idea mi è stata facile. – Roland

risposta

45
DF <- data.frame(x=letters[1:5], y=1:5, stringsAsFactors=FALSE) 

str(DF) 
#'data.frame': 5 obs. of 2 variables: 
# $ x: chr "a" "b" "c" "d" ... 
# $ y: int 1 2 3 4 5 

L'(fastidioso) predefinito di as.data.frame è quello di trasformare tutte le colonne di caratteri in colonne fattore. Puoi usare quello qui:

DF <- as.data.frame(unclass(DF)) 
str(DF) 
#'data.frame': 5 obs. of 2 variables: 
# $ x: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5 
# $ y: int 1 2 3 4 5 
77

La risposta di Roland è ottima per questo problema specifico, ma ho pensato di condividere un approccio più generalizzato.

DF <- data.frame(x = letters[1:5], y = 1:5, z = LETTERS[1:5], 
       stringsAsFactors=FALSE) 
str(DF) 
# 'data.frame': 5 obs. of 3 variables: 
# $ x: chr "a" "b" "c" "d" ... 
# $ y: int 1 2 3 4 5 
# $ z: chr "A" "B" "C" "D" ... 

## The conversion 
DF[sapply(DF, is.character)] <- lapply(DF[sapply(DF, is.character)], 
             as.factor) 
str(DF) 
# 'data.frame': 5 obs. of 3 variables: 
# $ x: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5 
# $ y: int 1 2 3 4 5 
# $ z: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5 

Per la conversione, il lato sinistro della assegnazione (DF[sapply(DF, is.character)]) sottoinsiemi le colonne che sono carattere. Nella parte destra, per quel sottoinsieme, usi lapply per eseguire qualsiasi conversione tu debba fare. R è abbastanza intelligente da sostituire le colonne originali con i risultati.

La cosa a portata di mano di questo è se si voleva andare nella direzione opposta o fare altre conversioni, è semplice come cambiare ciò che stai cercando a sinistra e specificare cosa si vuole cambiare per sulla destra.

+0

Grazie, molto utile, specialmente dopo una richiesta RMySQL che fornisce un dataframe di soli vettori di caratteri. Basta non dimenticare (come me) di impostare il tipo corretto di logico numerico, ecc. Nelle colonne che non sono caratteri in anticipo. –

16

Come @Raf Z ha commentato questo question, dplyr ora ha mutate_if. Super utile, semplice e leggibile.

> str(df) 
'data.frame': 5 obs. of 5 variables: 
$ A: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5 
$ B: int 1 2 3 4 5 
$ C: logi TRUE TRUE FALSE FALSE TRUE 
$ D: chr "a" "b" "c" "d" ... 
$ E: chr "A a" "B b" "C c" "D d" ... 

> df <- df %>% mutate_if(is.character,as.factor) 

> str(df) 
'data.frame': 5 obs. of 5 variables: 
$ A: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5 
$ B: int 1 2 3 4 5 
$ C: logi TRUE TRUE FALSE FALSE TRUE 
$ D: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5 
$ E: Factor w/ 5 levels "A a","B b","C c",..: 1 2 3 4 5 
1

Ho usato un ciclo semplice for. Come risposta @ A5C1D2H2I1M1N2O1R2T1, lapply è una bella soluzione. Ma se si convertono tutte le colonne, sarà necessario un data.frame prima, altrimenti si finirà con uno list. Piccole differenze di tempo di esecuzione.

mm2N=mm2New[,10:18] 
str(mm2N) 
'data.frame': 35487 obs. of 9 variables: 
$ bb : int 4 6 2 3 3 2 5 2 1 2 ... 
$ vabb : int -3 -3 -2 -2 -3 -1 0 0 3 3 ... 
$ bb55 : int 7 6 3 4 4 4 9 2 5 4 ... 
$ vabb55: int -3 -1 0 -1 -2 -2 -3 0 -1 3 ... 
$ zr : num 0 -2 -1 1 -1 -1 -1 1 1 0 ... 
$ z55r : num -2 -2 0 1 -2 -2 -2 1 -1 1 ... 
$ fechar: num 0 -1 1 0 1 1 0 0 1 0 ... 
$ varr : num 3 3 1 1 1 1 4 1 1 3 ... 
$ minmax: int 3 0 4 6 6 6 0 6 6 1 ... 

# For solution 
t1=Sys.time() 
for(i in 1:ncol(mm2N)) mm2N[,i]=as.factor(mm2N[,i]) 
Sys.time()-t1 
Time difference of 0.2020121 secs 
str(mm2N) 
'data.frame': 35487 obs. of 9 variables: 
$ bb : Factor w/ 6 levels "1","2","3","4",..: 4 6 2 3 3 2 5 2 1 2 ... 
$ vabb : Factor w/ 7 levels "-3","-2","-1",..: 1 1 2 2 1 3 4 4 7 7 ... 
$ bb55 : Factor w/ 8 levels "2","3","4","5",..: 6 5 2 3 3 3 8 1 4 3 ... 
$ vabb55: Factor w/ 7 levels "-3","-2","-1",..: 1 3 4 3 2 2 1 4 3 7 ... 
$ zr : Factor w/ 5 levels "-2","-1","0",..: 3 1 2 4 2 2 2 4 4 3 ... 
$ z55r : Factor w/ 5 levels "-2","-1","0",..: 1 1 3 4 1 1 1 4 2 4 ... 
$ fechar: Factor w/ 3 levels "-1","0","1": 2 1 3 2 3 3 2 2 3 2 ... 
$ varr : Factor w/ 5 levels "1","2","3","4",..: 3 3 1 1 1 1 4 1 1 3 ... 
$ minmax: Factor w/ 7 levels "0","1","2","3",..: 4 1 5 7 7 7 1 7 7 2 ... 

#lapply solution 
mm2N=mm2New[,10:18] 
t1=Sys.time() 
mm2N <- lapply(mm2N, as.factor) 
Sys.time()-t1 
Time difference of 0.209012 secs 
str(mm2N) 
List of 9 
$ bb : Factor w/ 6 levels "1","2","3","4",..: 4 6 2 3 3 2 5 2 1 2 ... 
$ vabb : Factor w/ 7 levels "-3","-2","-1",..: 1 1 2 2 1 3 4 4 7 7 ... 
$ bb55 : Factor w/ 8 levels "2","3","4","5",..: 6 5 2 3 3 3 8 1 4 3 ... 
$ vabb55: Factor w/ 7 levels "-3","-2","-1",..: 1 3 4 3 2 2 1 4 3 7 ... 
$ zr : Factor w/ 5 levels "-2","-1","0",..: 3 1 2 4 2 2 2 4 4 3 ... 
$ z55r : Factor w/ 5 levels "-2","-1","0",..: 1 1 3 4 1 1 1 4 2 4 ... 
$ fechar: Factor w/ 3 levels "-1","0","1": 2 1 3 2 3 3 2 2 3 2 ... 
$ varr : Factor w/ 5 levels "1","2","3","4",..: 3 3 1 1 1 1 4 1 1 3 ... 
$ minmax: Factor w/ 7 levels "0","1","2","3",..: 4 1 5 7 7 7 1 7 7 2 ... 

#data.frame lapply solution 
mm2N=mm2New[,10:18] 
t1=Sys.time() 
mm2N <- data.frame(lapply(mm2N, as.factor)) 
Sys.time()-t1 
Time difference of 0.2010119 secs 
str(mm2N) 
'data.frame': 35487 obs. of 9 variables: 
$ bb : Factor w/ 6 levels "1","2","3","4",..: 4 6 2 3 3 2 5 2 1 2 ... 
$ vabb : Factor w/ 7 levels "-3","-2","-1",..: 1 1 2 2 1 3 4 4 7 7 ... 
$ bb55 : Factor w/ 8 levels "2","3","4","5",..: 6 5 2 3 3 3 8 1 4 3 ... 
$ vabb55: Factor w/ 7 levels "-3","-2","-1",..: 1 3 4 3 2 2 1 4 3 7 ... 
$ zr : Factor w/ 5 levels "-2","-1","0",..: 3 1 2 4 2 2 2 4 4 3 ... 
$ z55r : Factor w/ 5 levels "-2","-1","0",..: 1 1 3 4 1 1 1 4 2 4 ... 
$ fechar: Factor w/ 3 levels "-1","0","1": 2 1 3 2 3 3 2 2 3 2 ... 
$ varr : Factor w/ 5 levels "1","2","3","4",..: 3 3 1 1 1 1 4 1 1 3 ... 
$ minmax: Factor w/ 7 levels "0","1","2","3",..: 4 1 5 7 7 7 1 7 7 2 ... 
0

Il modo più semplice sarebbe utilizzare il codice riportato di seguito. Automatizzerebbe l'intero processo di conversione di tutte le variabili come fattori in un dataframe in R. ha funzionato perfettamente bene per me. food_cat qui è il set di dati che sto usando. Cambialo a quello su cui stai lavorando.

for(i in 1:ncol(food_cat)){ 

food_cat[,i] <- as.factor(food_cat[,i]) 

} 
Problemi correlati