Especifique el formato de fecha personalizado para el argumento colClasses en read.table / read.csv


101

Pregunta:

¿Hay alguna forma de especificar el formato de fecha cuando se usa el argumento colClasses en read.table / read.csv?

(Me doy cuenta de que puedo convertir después de la importación, pero con muchas columnas de fecha como esta, sería más fácil hacerlo en el paso de importación)


Ejemplo:

Tengo un .csv con columnas de fecha en el formato %d/%m/%Y.

dataImport <- read.csv("data.csv", colClasses = c("factor","factor","Date"))

Esto hace que la conversión sea incorrecta. Por ejemplo, se 15/07/2008convierte en 0015-07-20.


Código reproducible:

data <- 
structure(list(func_loc = structure(c(1L, 2L, 3L, 3L, 3L, 3L, 
3L, 4L, 4L, 5L), .Label = c("3076WAG0003", "3076WAG0004", "3076WAG0007", 
"3076WAG0009", "3076WAG0010"), class = "factor"), order_type = structure(c(3L, 
3L, 1L, 1L, 1L, 1L, 2L, 2L, 3L, 1L), .Label = c("PM01", "PM02", 
"PM03"), class = "factor"), actual_finish = structure(c(4L, 6L, 
1L, 2L, 3L, 7L, 1L, 8L, 1L, 5L), .Label = c("", "11/03/2008", 
"14/08/2008", "15/07/2008", "17/03/2008", "19/01/2009", "22/09/2008", 
"6/09/2007"), class = "factor")), .Names = c("func_loc", "order_type", 
"actual_finish"), row.names = c(NA, 10L), class = "data.frame")


write.csv(data,"data.csv", row.names = F)                                                        

dataImport <- read.csv("data.csv")
str(dataImport)
dataImport

dataImport <- read.csv("data.csv", colClasses = c("factor","factor","Date"))
str(dataImport)
dataImport

Y así es como se ve la salida:

salida de código


Una forma hackear de hacer esto sería crear su propia versión read.tabley agregar un formatargumento al que se le pasa as.Date. Sin embargo, no me sorprendería que hubiera una forma mejor en la que no estoy pensando.
joran

Respuestas:


158

Puede escribir su propia función que acepte una cadena y la convierta en una Fecha usando el formato que desee, luego use el setAspara configurarlo como un asmétodo. Entonces puede usar su función como parte de colClasses.

Tratar:

setAs("character","myDate", function(from) as.Date(from, format="%d/%m/%Y") )

tmp <- c("1, 15/08/2008", "2, 23/05/2010")
con <- textConnection(tmp)

tmp2 <- read.csv(con, colClasses=c('numeric','myDate'), header=FALSE)
str(tmp2)

Luego modifíquelo si es necesario para trabajar con sus datos.

Editar ---

Es posible que desee ejecutar setClass('myDate')primero para evitar la advertencia (puede ignorar la advertencia, pero puede resultar molesto si hace esto con frecuencia y esta es una llamada simple que se deshace de ella).


2
¡Wow - setAs es un salvavidas! ¿Cómo nunca antes había visto esta función?
user295691

4
Tenga en cuenta que es posible que obtenga una advertencia "sin definición para la clase" myDate "" como se detalla en esta pregunta .
Danny D'Amours

1
¿Qué se setMethod('myDate')supone que debo hacer? Ejecutarlo solo me da un error ...
Josh O'Brien

1
@ JoshO'Brien, lo siento, eso debería haber sido setClass(arreglado ahora). Lo que hace es evitar que se setAsemita una advertencia acerca de que 'myDate' no existe como clase. La advertencia es inofensiva y todo sigue funcionando, pero configurar la clase significa que ni siquiera verá la advertencia.
Greg Snow

1
@MySchizoBuddy, si solo tiene una columna de fecha y lo está haciendo una vez, probablemente no importe de qué manera lo haga. Pero si tiene varias columnas en su conjunto de datos que son fechas, entonces creo que este enfoque probablemente sería más simple que cambiar cada una de las columnas después de leer.
Greg Snow

25

Si solo hay 1 formato de fecha que desea cambiar, puede usar el Defaultspaquete para cambiar el formato predeterminado dentro deas.Date.character

library(Defaults)
setDefaults('as.Date.character', format = '%d/%M/%Y')
dataImport <- read.csv("data.csv", colClasses = c("factor","factor","Date"))
str(dataImport)
## 'data.frame':    10 obs. of  3 variables:
##  $ func_loc     : Factor w/ 5 levels "3076WAG0003",..: 1 2 3 3 3 3 3 4 4 5
##  $ order_type   : Factor w/ 3 levels "PM01","PM02",..: 3 3 1 1 1 1 2 2 3 1
##  $ actual_finish: Date, format: "2008-10-15" "2009-10-19" NA "2008-10-11" ...

Creo que la respuesta de @Greg Snow es mucho mejor, ya que no cambia el comportamiento predeterminado de una función de uso frecuente.


7

En caso de que necesite tiempo también:

setClass('yyyymmdd-hhmmss')
setAs("character","yyyymmdd-hhmmss", function(from) as.POSIXct(from, format="%Y%m%d-%H%M%S"))
d <- read.table(colClasses="yyyymmdd-hhmmss", text="20150711-130153")
str(d)
## 'data.frame':    1 obs. of  1 variable:
## $ V1: POSIXct, format: "2015-07-11 13:01:53"

2

Hace mucho tiempo, mientras tanto, Hadley Wickham resolvió el problema. Así que hoy en día la solución se reduce a un delineador:

library(readr)
data <- read_csv("data.csv", 
                  col_types = cols(actual_finish = col_datetime(format = "%d/%m/%Y")))

Tal vez incluso queramos deshacernos de cosas innecesarias:

data <- as.data.frame(data)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.