Geben Sie das benutzerdefinierte Datumsformat für das Argument colClasses in read.table / read.csv an

101

Frage:

Gibt es eine Möglichkeit, das Datumsformat anzugeben, wenn das Argument colClasses in read.table / read.csv verwendet wird?

(Mir ist klar, dass ich nach dem Import konvertieren kann, aber mit vielen solchen Datumsspalten wäre es einfacher, dies im Importschritt zu tun.)


Beispiel:

Ich habe eine CSV mit Datumsspalten im Format %d/%m/%Y.

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

Dies führt zu einer falschen Konvertierung. Zum Beispiel 15/07/2008wird 0015-07-20.


Reproduzierbarer Code:

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

Und so sieht die Ausgabe aus:

Code-Ausgabe

Tommy O'Dell
quelle
Ein hackiger Weg, dies zu tun, wäre, eine eigene Version von zu erstellen read.tableund ein formatArgument hinzuzufügen , das an weitergegeben wird as.Date. Es würde mich nicht wundern, wenn es einen besseren Weg gibt, an den ich nicht denke.
Joran

Antworten:

158

Sie können Ihre eigene Funktion schreiben, die eine Zeichenfolge akzeptiert und sie im gewünschten Format in ein Datum konvertiert. Anschließend können Sie setAssie mit der asMethode als Methode festlegen . Dann können Sie Ihre Funktion als Teil der colClasses verwenden.

Versuchen:

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)

Ändern Sie dann bei Bedarf, um für Ihre Daten zu arbeiten.

Bearbeiten ---

Möglicherweise möchten Sie setClass('myDate')zuerst ausgeführt werden, um die Warnung zu vermeiden (Sie können die Warnung ignorieren, aber es kann ärgerlich werden, wenn Sie dies häufig tun, und dies ist ein einfacher Aufruf, der sie beseitigt).

Greg Snow
quelle
2
Wow - setAs ist ein Lebensretter! Wie habe ich diese Funktion noch nie gesehen?
user295691
4
Beachten Sie, dass Sie möglicherweise die Warnung "Keine Definition für Klasse" myDate "erhalten, wie in dieser Frage beschrieben .
Danny D'Amours
1
Was setMethod('myDate')soll tun? Das Ausführen gibt mir nur einen Fehler ...
Josh O'Brien
1
@ JoshO'Brien, sorry das hätte sein sollen setClass(jetzt behoben). Es wird verhindert setAs, dass eine Warnung ausgegeben wird, dass 'myDate' nicht als Klasse vorhanden ist. Die Warnung ist harmlos und alles funktioniert immer noch. Wenn Sie jedoch die Klasse festlegen, wird die Warnung nicht einmal angezeigt.
Greg Snow
1
@MySchizoBuddy, Wenn Sie nur eine Datumsspalte haben und dies einmal tun, spielt es wahrscheinlich keine Rolle, wie Sie es tun. Wenn Ihr Datensatz jedoch mehrere Spalten enthält, bei denen es sich um Datumsangaben handelt, ist dieser Ansatz wahrscheinlich einfacher, als jede der Spalten nach dem Lesen zu ändern.
Greg Snow
25

Wenn Sie nur ein Datumsformat ändern möchten, können Sie Defaultsdas Standardformat innerhalb des Pakets ändernas.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" ...

Ich denke, die Antwort von @Greg Snow ist weitaus besser, da sie das Standardverhalten einer häufig verwendeten Funktion nicht ändert.

mnel
quelle
7

Falls Sie auch Zeit brauchen:

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"
Mark Rajcok
quelle
2

Vor langer Zeit wurde das Problem von Hadley Wickham gelöst. Heutzutage ist die Lösung auf einen Oneliner reduziert:

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

Vielleicht wollen wir sogar unnötiges Zeug loswerden:

data <- as.data.frame(data)
Andri Signorell
quelle