numericas - Convertir el tipo de varias columnas de un marco de datos a la vez
convertir factor en variable numerica r (8)
Además de la respuesta de @ joran, en la que convert.magic
no conservará los valores numéricos en la conversión de factor a número:
convert.magic <- function(obj,types){
out <- lapply(1:length(obj),FUN = function(i){FUN1 <- switch(types[i],
character = as.character,numeric = as.numeric,factor = as.factor); FUN1(obj[,i])})
names(out) <- colnames(obj)
as.data.frame(out,stringsAsFactors = FALSE)
}
foo<-data.frame(x=c(1:10),
y=c("red", "red", "red", "blue", "blue",
"blue", "yellow", "yellow", "yellow",
"green"),
z=Sys.Date()+c(1:10))
foo$x<-as.character(foo$x)
foo$y<-as.character(foo$y)
foo$z<-as.numeric(foo$z)
str(foo)
# ''data.frame'': 10 obs. of 3 variables:
# $ x: chr "1" "2" "3" "4" ...
# $ y: chr "red" "red" "red" "blue" ...
# $ z: num 16777 16778 16779 16780 16781 ...
foo.factors <- convert.magic(foo, rep("factor", 3))
str(foo.factors) # all factors
foo.numeric.not.preserved <- convert.magic(foo.factors, c("numeric", "character", "numeric"))
str(foo.numeric.not.preserved)
# ''data.frame'': 10 obs. of 3 variables:
# $ x: num 1 3 4 5 6 7 8 9 10 2
# $ y: chr "red" "red" "red" "blue" ...
# $ z: num 1 2 3 4 5 6 7 8 9 10
# z comes out as 1 2 3...
Lo siguiente debe preservar los valores numéricos:
## as.numeric function that preserves numeric values when converting factor to numeric
as.numeric.mod <- function(x) {
if(is.factor(x))
as.numeric(levels(x))[x]
else
as.numeric(x)
}
## The same than in @joran''s answer, except for as.numeric.mod
convert.magic <- function(obj,types){
out <- lapply(1:length(obj),FUN = function(i){FUN1 <- switch(types[i],
character = as.character,numeric = as.numeric.mod, factor = as.factor); FUN1(obj[,i])})
names(out) <- colnames(obj)
as.data.frame(out,stringsAsFactors = FALSE)
}
foo.numeric <- convert.magic(foo.factors, c("numeric", "character", "numeric"))
str(foo.numeric)
# ''data.frame'': 10 obs. of 3 variables:
# $ x: num 1 2 3 4 5 6 7 8 9 10
# $ y: chr "red" "red" "red" "blue" ...
# $ z: num 16777 16778 16779 16780 16781 ...
# z comes out with the correct numeric values
Me parece que paso mucho tiempo creando un marco de datos a partir de un archivo, base de datos o algo así, y luego convirtiendo cada columna en el tipo en el que la quería (numérica, factor, carácter, etc.). ¿Hay alguna manera de hacer esto en un solo paso, posiblemente dando un vector de tipos?
foo<-data.frame(x=c(1:10),
y=c("red", "red", "red", "blue", "blue",
"blue", "yellow", "yellow", "yellow",
"green"),
z=Sys.Date()+c(1:10))
foo$x<-as.character(foo$x)
foo$y<-as.character(foo$y)
foo$z<-as.numeric(foo$z)
en lugar de los últimos tres comandos, me gustaría hacer algo como
foo<-convert.magic(foo, c(character, character, numeric))
Encuentro que me encuentro con esto mucho también. Esto se trata de cómo importar datos. Todas las funciones de lectura ... () tienen algún tipo de opción para especificar que no se conviertan cadenas de caracteres en un factor. Lo que significa que las cadenas de texto se mantendrán como caracteres y las que parezcan números se mantendrán como números. Surge un problema cuando tienes elementos que están vacíos y no NA. Pero, de nuevo, na.strings = c ("", ...) debería resolver eso también. Comenzaría analizando detenidamente su proceso de importación y ajustándolo en consecuencia.
Pero siempre puedes crear una función e impulsar esta cadena.
convert.magic <- function(x, y=NA) {
for(i in 1:length(y)) {
if (y[i] == "numeric") {
x[i] <- as.numeric(x[[i]])
}
if (y[i] == "character")
x[i] <- as.character(x[[i]])
}
return(x)
}
foo <- convert.magic(foo, c("character", "character", "numeric"))
> str(foo)
''data.frame'': 10 obs. of 3 variables:
$ x: chr "1" "2" "3" "4" ...
$ y: chr "red" "red" "red" "blue" ...
$ z: num 15254 15255 15256 15257 15258 ...
Me encontré con algo así con el método de búsqueda de RSQLite ... los resultados vuelven como tipos de datos atómicos. En mi caso, fue una marca de fecha y hora lo que me estaba causando frustración. Descubrí que la función setAs
es muy útil para ayudar a hacer el trabajo como se espera. Aquí está mi pequeño caso de ejemplo.
##data.frame conversion function
convert.magic2 <- function(df,classes){
out <- lapply(1:length(classes),
FUN = function(classIndex){as(df[,classIndex],classes[classIndex])})
names(out) <- colnames(df)
return(data.frame(out))
}
##small example case
tmp.df <- data.frame(''dt''=c("2013-09-02 09:35:06", "2013-09-02 09:38:24", "2013-09-02 09:38:42", "2013-09-02 09:38:42"),
''v''=c(''1'',''2'',''3'',''4''),
stringsAsFactors=FALSE)
classes=c(''POSIXct'',''numeric'')
str(tmp.df)
#confirm that it has character datatype columns
## ''data.frame'': 4 obs. of 2 variables:
## $ dt: chr "2013-09-02 09:35:06" "2013-09-02 09:38:24" "2013-09-02 09:38:42" "2013-09-02 09:38:42"
## $ v : chr "1" "2" "3" "4"
##is the dt column coerceable to POSIXct?
canCoerce(tmp.df$dt,"POSIXct")
## [1] FALSE
##and the conver.magic2 function fails also:
tmp.df.n <- convert.magic2(tmp.df,classes)
## Error in as(df[, classIndex], classes[classIndex]) :
## no method or default for coercing “character” to “POSIXct”
##ittle reading reveals the setAS function
setAs(''character'', ''POSIXct'', function(from){return(as.POSIXct(from))})
##better answer for canCoerce
canCoerce(tmp.df$dt,"POSIXct")
## [1] TRUE
##better answer from conver.magic2
tmp.df.n <- convert.magic2(tmp.df,classes)
##column datatypes converted as I would like them!
str(tmp.df.n)
## ''data.frame'': 4 obs. of 2 variables:
## $ dt: POSIXct, format: "2013-09-02 09:35:06" "2013-09-02 09:38:24" "2013-09-02 09:38:42" "2013-09-02 09:38:42"
## $ v : num 1 2 3 4
Sé que es bastante tarde para responder, pero usar un ciclo junto con la función de atributos es una solución simple a su problema.
names <-c(x, y, z)
chclass <-c("character","character","numeric")
for (i in (1:length(names))){
attributes(foo[,(names[i])])$class <-chclass[i]
}
Si desea detectar automáticamente el tipo de datos de las columnas en lugar de especificarlo manualmente (por ejemplo, después de la limpieza de los datos, etc.), la función type.convert()
puede ayudar.
La función type.convert()
toma un vector de caracteres e intenta determinar el tipo óptimo para todos los elementos (lo que significa que debe aplicarse una vez por columna).
df[] <- lapply(df, function(x) type.convert(as.character(x)))
Como amo dplyr
, prefiero:
library(dplyr)
df <- df %>% mutate_all(funs(type.convert(as.character(.))))
Transformar es lo que pareces describir:
foo <- transform(foo, x=as.character(x), y=as.character(y), z=as.numeric(z))
Una solución data.table algo simple, aunque tomará algunos pasos si cambia a muchos tipos de columnas diferentes.
dt <- data.table( x=c(1:10), y=c(10:20), z=c(10:20), name=letters[1:10])
dt <- dt[, lapply(.SD, as.numeric), by= name]
Esto cambiará todas las columnas excepto las especificadas by
por numéricas (o lo que sea que hayas configurado en lapply
)
Editar Consulte this pregunta relacionada para obtener algunas simplificaciones y extensiones sobre esta idea básica.
Mi comentario a la respuesta de Brandon usando el switch
:
convert.magic <- function(obj,types){
for (i in 1:length(obj)){
FUN <- switch(types[i],character = as.character,
numeric = as.numeric,
factor = as.factor)
obj[,i] <- FUN(obj[,i])
}
obj
}
out <- convert.magic(foo,c(''character'',''character'',''numeric''))
> str(out)
''data.frame'': 10 obs. of 3 variables:
$ x: chr "1" "2" "3" "4" ...
$ y: chr "red" "red" "red" "blue" ...
$ z: num 15254 15255 15256 15257 15258 ...
Para marcos de datos verdaderamente grandes, es posible que desee utilizar lapply
lugar del bucle for
:
convert.magic1 <- function(obj,types){
out <- lapply(1:length(obj),FUN = function(i){FUN1 <- switch(types[i],character = as.character,numeric = as.numeric,factor = as.factor); FUN1(obj[,i])})
names(out) <- colnames(obj)
as.data.frame(out,stringsAsFactors = FALSE)
}
Al hacer esto, tenga en cuenta algunas de las complejidades de la coerción de datos en R. Por ejemplo, la conversión de factor a numérico a menudo implica as.numeric(as.character(...))
. Además, tenga en cuenta el comportamiento predeterminado de data.frame()
y as.data.frame()
de convertir el carácter en factor.