Specificare il formato data personalizzato per l'argomento colClasses in read.table / read.csv


101

Domanda:

C'è un modo per specificare il formato della data quando si utilizza l'argomento colClasses in read.table / read.csv?

(Mi rendo conto di poter convertire dopo l'importazione, ma con molte colonne di date come questa, sarebbe più facile farlo nella fase di importazione)


Esempio:

Ho un .csv con colonne di date nel formato %d/%m/%Y.

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

Questo fa sbagliare la conversione. Ad esempio, 15/07/2008diventa 0015-07-20.


Codice riproducibile:

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

Ed ecco come appare l'output:

output del codice


Un modo hacker per farlo sarebbe creare la tua versione di read.tablee aggiungere un formatargomento che viene passato a as.Date. Non sarei sorpreso se ci fosse un modo migliore a cui non sto pensando, però.
joran

Risposte:


158

Puoi scrivere la tua funzione che accetta una stringa e la converte in una data utilizzando il formato che desideri, quindi usa il setAsper impostarla come asmetodo. Quindi puoi usare la tua funzione come parte delle colClass.

Provare:

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)

Quindi modifica se necessario per lavorare con i tuoi dati.

Modificare ---

Potresti voler eseguire setClass('myDate')prima per evitare l'avviso (puoi ignorare l'avviso, ma può diventare fastidioso se lo fai spesso e questa è una semplice chiamata che lo elimina).


2
Wow - setAs è un salvavita! Come non ho mai visto questa funzione prima?
user295691

4
Nota che potresti ricevere un avviso "nessuna definizione per la classe" miaData "" come descritto in dettaglio in questa domanda .
Danny D'Amours

1
Cosa setMethod('myDate')dovrebbe fare? L'esecuzione mi dà solo un errore ...
Josh O'Brien

1
@ JoshO'Brien, mi dispiace che avrebbe dovuto essere setClass(risolto ora). Quello che fa è impedire setAsdi emettere un avviso riguardo a "myDate" che non esiste come classe. L'avviso è innocuo e tutto funziona ancora, ma impostare la classe significa che non vedi nemmeno l'avviso.
Greg Snow il

1
@MySchizoBuddy, se hai solo una colonna della data e lo stai facendo una volta, probabilmente non importa in che modo lo fai. Ma se hai più colonne nel tuo set di dati che sono date, allora penso che questo approccio sarebbe probabilmente più semplice che cambiare ciascuna delle colonne dopo la lettura.
Greg Snow

25

Se è presente un solo formato di data che desideri modificare, puoi utilizzare il Defaultspacchetto per modificare il formato predefinito all'interno dias.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" ...

Penso che la risposta di @Greg Snow sia di gran lunga migliore, in quanto non modifica il comportamento predefinito di una funzione usata spesso.


7

Se hai bisogno di tempo anche:

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

Molto tempo fa, nel frattempo, il problema è stato risolto da Hadley Wickham. Quindi al giorno d'oggi la soluzione si riduce a un oneliner:

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

Forse vogliamo anche sbarazzarci di cose non necessarie:

data <- as.data.frame(data)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.