2012-02-09 14 views
10

Usted sabe cómo puede suministrar un vector de nombres a un marco de datos para cambiar los nombres de columna o fila de un marco de datos. ¿Existe un método similar para proporcionar un vector de nombres que altere la clase de cada columna en un marco de datos? Puede hacer esto cuando lea en un marco de datos con read.table usando colClasses. ¿Qué pasa si el marco de datos se crea dentro de R?suministra un vector a "clases" de marco de datos

DF <- as.data.frame(matrix(rnorm(25), 5, 5)) 
str(DF) #all numeric modes 

names(DF) <- c("A", "A2", "B", "B2", "Z") #I want something like this for classes 
some_classes_function_like_names(DF) <- c(rep("character", 3), rep("factor", 2)) 

#I can do it like this but this seems inefficient 
DF[, 1:3] <- lapply(DF[, 1:3], as.character) 
DF[, 4:5] <- lapply(DF[, 4:5], as.factor) 

str(DF) 

EDIT: He cambiado sapply arriba para lapply como sapply no tiene sentido.

EDIT 2: Si hay una manera de escribir una función definida por el usuario que sería suficiente, así

Respuesta

5

Parece class(x) <- "factor" no funciona y tampoco lo hace as(x, "factor"), por lo que no saben de una manera directa de hacerlo Lo que quieras.

... Pero de una manera un poco más explícita es:

# Coerces data.frame columns to the specified classes 
colClasses <- function(d, colClasses) { 
    colClasses <- rep(colClasses, len=length(d)) 
    d[] <- lapply(seq_along(d), function(i) switch(colClasses[i], 
     numeric=as.numeric(d[[i]]), 
     character=as.character(d[[i]]), 
     Date=as.Date(d[[i]], origin='1970-01-01'), 
     POSIXct=as.POSIXct(d[[i]], origin='1970-01-01'), 
     factor=as.factor(d[[i]]), 
     as(d[[i]], colClasses[i]))) 
    d 
} 

# Example usage 
DF <- as.data.frame(matrix(rnorm(25), 5, 5)) 
DF2 <- colClasses(DF, c(rep("character", 3), rep("factor", 2))) 
str(DF2) 

DF3 <- colClasses(DF, 'Date') 
str(DF3) 

Un par de cosas: se puede añadir más casos, según sea necesario. Y la primera línea de la función le permite llamar con un solo nombre de clase. El último caso "predeterminado" de switch llama a la función as y su kilometraje puede variar.

+0

@ Tommy Esperaba la respuesta "Usted sabe que ya hay una función base que lo hace fácilmente". Tus funciones funcionan bien. Voy a incluirlo en mi .First() como una función de conveniencia para mí. De hecho, estoy un poco sorprendido de que el equipo R-core aún no haya implementado algo así, especialmente porque parece ser parte de read.table. Gracias. –

+0

@Tyler Compartí tu sorpresa. Durante mucho tiempo he buscado una función de base para hacer esto, y por lo general tomo un enfoque ad hoc sobre la marcha. Sería genial si el equipo R-core considerara esto en la base. – digitalmaps

8

Prueba esto:

toCls <- function(x, cls) do.call(paste("as", cls, sep = "."), list(x)) 
replace(DF,, Map(toCls, DF, cls)) 

Segundo ejemplo. Pruebe también este ejemplo (que permite que NA se use para cualquier columna cuya clase no se cambie). Cargamos el paquete de zoo ya que proporciona una versión de as.Date que tiene un origen predeterminado y definimos nuestro propio as.POSIXct2 para evitar tener que especificar el origen.

library(zoo) # supplies alternate as.Date with a default origin 
as.NA <- identity 
as.POSIXct2 <- function(x) as.POSIXct(x, origin = "1970-01-01") 

cls2 <- c("character", "Date", NA, "factor", "POSIXct2") 
replace(DF,, Map(toCls, DF, cls2)) 

Tenga en cuenta que su único al convertir los números a "Date" o "POSIXct" que hay consideraciones de origen y al convertir las cadenas de caracteres tales como "2000-01-01" tendrían que ser especificada en cualquier caso, no tiene origen por lo que para este tipo de situaciones no necesitaríamos a cargar zoológico y no necesitaríamos nuestra propia versión de as.POSIXct.

EDITAR: Agregó otro ejemplo.

Cuestiones relacionadas