Cambia la class da fattore a numerico di molte colonne in un frame di dati

Qual è il modo più veloce / migliore per modificare un numero elevato di colonne in base al fattore numerico?

Ho usato il seguente codice ma sembra che abbia riordinato i miei dati.

> head(stats[,1:2]) rk team 1 1 Washington Capitals* 2 2 San Jose Sharks* 3 3 Chicago Blackhawks* 4 4 Phoenix Coyotes* 5 5 New Jersey Devils* 6 6 Vancouver Canucks* for(i in c(1,3:ncol(stats))) { stats[,i]  head(stats[,1:2]) rk team 1 2 Washington Capitals* 2 13 San Jose Sharks* 3 24 Chicago Blackhawks* 4 26 Phoenix Coyotes* 5 27 New Jersey Devils* 6 28 Vancouver Canucks* 

Qual è il modo migliore, a meno di nominare ogni colonna come in:

 df$colname <- as.numeric(ds$colname) 

Oltre alla risposta di Ramnath, il comportamento che si sta verificando è dovuto al fatto che as.numeric(x) restituisce la rappresentazione numerica interna del fattore x al livello R. Se si desidera conservare i numeri che sono i livelli del fattore (piuttosto che la loro rappresentazione interna), è necessario convertire in carattere tramite as.character() prima come nell’esempio di Ramnath.

Il ciclo for è ragionevole quanto una chiamata in corso e potrebbe essere leggermente più leggibile su quale sia l’intenzione del codice. Basta cambiare questa linea:

 stats[,i] <- as.numeric(stats[,i]) 

leggere

 stats[,i] <- as.numeric(as.character(stats[,i])) 

Questa è la FAQ 7.10 nelle FAQ R.

HTH

Devi stare attento mentre cambi i fattori in numerico. Ecco una riga di codice che cambierebbe un insieme di colonne da fattore a numerico. Presumo qui che le colonne da modificare in numerico siano 1, 3, 4 e 5 rispettivamente. Potresti cambiarlo di conseguenza

 cols = c(1, 3, 4, 5); df[,cols] = apply(df[,cols], 2, function(x) as.numeric(as.character(x))); 

Questo può essere fatto in una riga, non c’è bisogno di un ciclo, che si tratti di un ciclo for o di una domanda. Utilizza invece unlist ():

 # testdata Df <- data.frame( x = as.factor(sample(1:5,30,r=TRUE)), y = as.factor(sample(1:5,30,r=TRUE)), z = as.factor(sample(1:5,30,r=TRUE)), w = as.factor(sample(1:5,30,r=TRUE)) ) ## Df[,c("y","w")] <- as.numeric(as.character(unlist(Df[,c("y","w")]))) str(Df) 

Modifica: per il tuo codice, questo diventa:

 id <- c(1,3:ncol(stats))) stats[,id] <- as.numeric(as.character(unlist(stats[,id]))) 

Ovviamente, se si dispone di un frame di dati a una colonna e non si desidera che la riduzione automatica della dimensione di R lo converta in un vettore, è necessario aggiungere l'argomento drop=FALSE .

So che questa domanda è a lungo risolta, ma recentemente ho avuto un problema simile e penso di aver trovato una soluzione un po ‘più elegante e funzionale, anche se richiede il pacchetto magrittr.

 library(magrittr) cols = c(1, 3, 4, 5) df[,cols] %<>% lapply(function(x) as.numeric(as.character(x))) 

L’operatore %<>% mostra pipe e riassegna, che è molto utile per mantenere semplice la pulizia e la trasformazione dei dati. Ora la funzione di applicazione della lista è molto più semplice da leggere, specificando solo la funzione che desideri applicare.

Penso che ucfagls abbia trovato il motivo per cui il tuo ciclo non funziona.

Nel caso in cui ancora non volessi usare un loop, ecco la soluzione con lapply :

 factorToNumeric <- function(f) as.numeric(levels(f))[as.integer(f)] cols <- c(1, 3:ncol(stats)) stats[cols] <- lapply(stats[cols], factorToNumeric) 

Modificare. Ho trovato una soluzione più semplice. Sembra che as.matrix converta in carattere. Così

 stats[cols] <- as.numeric(as.matrix(stats[cols])) 

dovrebbe fare quello che vuoi

lapply è praticamente progettato per questo

 unfactorize<-c("colA","colB") df[,unfactorize]<-lapply(unfactorize, function(x) as.numeric(as.character(df[,x]))) 

Ho trovato questa funzione su un paio di altri thread duplicati e ho trovato un modo elegante e generale per risolvere questo problema. Questo thread si presenta per la maggior parte delle ricerche su questo argomento, quindi lo condivido qui per salvare un po ‘di tempo. Non mi fido di questo, quindi guarda i post originali qui e qui per i dettagli.

 df <- data.frame(x = 1:10, y = rep(1:2, 5), k = rnorm(10, 5,2), z = rep(c(2010, 2012, 2011, 2010, 1999), 2), j = c(rep(c("a", "b", "c"), 3), "d")) convert.magic <- function(obj, type){ FUN1 <- switch(type, character = as.character, numeric = as.numeric, factor = as.factor) out <- lapply(obj, FUN1) as.data.frame(out) } str(df) str(convert.magic(df, "character")) str(convert.magic(df, "factor")) df[, c("x", "y")] <- convert.magic(df[, c("x", "y")], "factor") 

Vorrei sottolineare che se si hanno NA in qualsiasi colonna, semplicemente l’uso di pedici non funzionerà. Se ci sono NA nel fattore, è necessario utilizzare lo script apply fornito da Ramnath.

Per esempio

 Df <- data.frame( x = c(NA,as.factor(sample(1:5,30,r=T))), y = c(NA,as.factor(sample(1:5,30,r=T))), z = c(NA,as.factor(sample(1:5,30,r=T))), w = c(NA,as.factor(sample(1:5,30,r=T))) ) Df[,c(1:4)] <- as.numeric(as.character(Df[,c(1:4)])) 

Restituisce il seguente:

 Warning message: NAs introduced by coercion > head(Df) xyzw 1 NA NA NA NA 2 NA NA NA NA 3 NA NA NA NA 4 NA NA NA NA 5 NA NA NA NA 6 NA NA NA NA 

Ma:

 Df[,c(1:4)]= apply(Df[,c(1:4)], 2, function(x) as.numeric(as.character(x))) 

Ritorna:

 > head(Df) xyzw 1 NA NA NA NA 2 2 3 4 1 3 1 5 3 4 4 2 3 4 1 5 5 3 5 5 6 4 2 4 4 

Ho avuto problemi nel convertire tutte le colonne in numerico con una chiamata apply() :

 apply(data, 2, as.numeric) 

Il problema si verifica perché alcune stringhe contenevano una virgola, ad es. “1.024.63” invece di “1024.63”, e R non apprezza questo modo di formattare i numeri. Quindi li ho rimossi e poi as.numeric() eseguito as.numeric() :

 data = as.data.frame(apply(data, 2, function(x) { y = str_replace_all(x, ",", "") #remove commas return(as.numeric(y)) #then convert })) 

Nota che questo richiede il caricamento del pacchetto stringr.

Questo è quello che ha funzionato per me. La funzione apply() tenta di forzare df in matrice e restituisce NA.

numeric.df <- as.data.frame(sapply(df, 2, as.numeric))

puoi usare la funzione unfactor() dal form del pacchetto “varhandle” CRAN:

 library("varhandle") my_iris <- data.frame(Sepal.Length = factor(iris$Sepal.Length), sample_id = factor(1:nrow(iris))) my_iris <- unfactor(my_iris)