Spécifiez le format de date personnalisé pour l'argument colClasses dans read.table / read.csv

101

Question:

Existe-t-il un moyen de spécifier le format de date lors de l'utilisation de l'argument colClasses dans read.table / read.csv?

(Je me rends compte que je peux convertir après l'importation, mais avec de nombreuses colonnes de date comme celle-ci, ce serait plus facile de le faire à l'étape d'importation)


Exemple:

J'ai un .csv avec des colonnes de date au format %d/%m/%Y.

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

Cela entraîne une erreur de conversion. Par exemple, 15/07/2008devient 0015-07-20.


Code reproductible:

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

Et voici à quoi ressemble la sortie:

sortie de code

Tommy O'Dell
la source
Une manière piratée de faire cela serait de créer votre propre version de read.tableet d'ajouter un formatargument qui est transmis à as.Date. Je ne serais pas surpris s'il existe une meilleure façon de ne pas penser.
joran

Réponses:

158

Vous pouvez écrire votre propre fonction qui accepte une chaîne et la convertit en date en utilisant le format souhaité, puis utilisez le setAspour la définir comme asméthode. Ensuite, vous pouvez utiliser votre fonction dans le cadre des colClasses.

Essayer:

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)

Puis modifiez si nécessaire pour travailler pour vos données.

Éditer ---

Vous voudrez peut-être exécuter d' setClass('myDate')abord pour éviter l'avertissement (vous pouvez ignorer l'avertissement, mais cela peut devenir ennuyeux si vous le faites beaucoup et c'est un simple appel qui vous en débarrasse).

Greg Snow
la source
2
Wow - setAs est une bouée de sauvetage! Comment n'ai-je jamais vu cette fonction auparavant?
user295691
4
Notez que vous pourriez obtenir un avertissement «pas de définition pour la classe« myDate »» comme détaillé dans cette question .
Danny D'Amours
1
Que setMethod('myDate')doit-on faire? L'exécuter me donne juste une erreur ...
Josh O'Brien
1
@ JoshO'Brien, désolé que cela aurait dû être setClass(corrigé maintenant). Ce qu'il fait est d'empêcher setAsd'émettre un avertissement concernant «myDate» qui n'existe pas en tant que classe. L'avertissement est inoffensif et tout fonctionne toujours, mais la définition de la classe signifie que vous ne voyez même pas l'avertissement.
Greg Snow
1
@MySchizoBuddy, Si vous n'avez qu'une seule colonne de date et que vous le faites une fois, la manière dont vous le faites n'a probablement pas d'importance. Mais si vous avez plusieurs colonnes dans votre ensemble de données qui sont des dates, je pense que cette approche serait probablement plus simple que de changer chacune des colonnes après la lecture.
Greg Snow
25

S'il n'y a qu'un seul format de date que vous souhaitez modifier, vous pouvez utiliser le Defaultspackage pour modifier le format par défaut dansas.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" ...

Je pense que la réponse de @Greg Snow est bien meilleure, car elle ne change pas le comportement par défaut d'une fonction souvent utilisée.

mnel
la source
7

Au cas où vous auriez besoin de temps aussi:

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
la source
2

Il y a longtemps, le problème a été résolu par Hadley Wickham. Donc, de nos jours, la solution est réduite à un seul revêtement:

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

Peut-être que nous voulons même nous débarrasser des choses inutiles:

data <- as.data.frame(data)
Andri Signorell
la source