Especifique o formato de data personalizado para o argumento colClasses em read.table / read.csv

101

Questão:

Existe uma maneira de especificar o formato de Data ao usar o argumento colClasses em read.table / read.csv?

(Sei que posso converter após a importação, mas com muitas colunas de data como esta, seria mais fácil fazer isso na etapa de importação)


Exemplo:

Eu tenho um .csv com colunas de data no formato %d/%m/%Y.

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

Isso torna a conversão errada. Por exemplo, 15/07/2008torna-se 0015-07-20.


Código reproduzível:

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

E aqui está a aparência da saída:

saída de código

Tommy O'Dell
fonte
Uma maneira hackeada de fazer isso seria criar sua própria versão de read.tablee adicionar um formatargumento que é passado para as.Date. Eu não ficaria surpreso se houvesse uma maneira melhor que eu não estou pensando, no entanto.
joran

Respostas:

158

Você pode escrever sua própria função que aceita uma string e a converte em uma Data usando o formato desejado e, em seguida, use o setAspara defini-la como um asmétodo. Em seguida, você pode usar sua função como parte das colClasses.

Experimentar:

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)

Em seguida, modifique se necessário para trabalhar com seus dados.

Editar ---

Você pode querer executar setClass('myDate')primeiro para evitar o aviso (você pode ignorar o aviso, mas pode ser irritante se você fizer isso com frequência e esta é uma chamada simples que elimina isso).

Greg Snow
fonte
2
Uau - setAs é um salva-vidas! Como nunca vi essa função antes?
user295691
4
Observe que você pode obter um aviso 'sem definição para a classe "myDate"', conforme detalhado nesta pergunta .
Danny D'Amours de
1
O que é setMethod('myDate')suposto fazer? Executá-lo apenas me dá um erro ...
Josh O'Brien
1
@ JoshO'Brien, desculpe isso deveria ter sido setClass(consertado agora). O que ele faz é evitar que setAsseja emitido um aviso sobre 'myDate' não existir como uma classe. O aviso é inofensivo e tudo ainda funciona, mas definir a classe significa que você nem mesmo vê o aviso.
Greg Snow
1
@MySchizoBuddy, Se você tem apenas uma coluna de data e está fazendo isso uma vez, provavelmente não importa de que maneira você o faz. Mas se você tiver várias colunas em seu conjunto de dados que são datas, então acho que essa abordagem provavelmente seria mais simples do que alterar cada uma das colunas após a leitura.
Greg Snow
25

Se houver apenas 1 formato de data que deseja alterar, você pode usar o Defaultspacote para alterar o formato padrão dentroas.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" ...

Acho que a resposta de @Greg Snow é muito melhor, pois não altera o comportamento padrão de uma função usada com frequência.

mnel
fonte
7

Caso precise de tempo também:

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
fonte
2

Há muito tempo, entretanto, o problema foi resolvido por Hadley Wickham. Então, hoje em dia, a solução é reduzida a uma linha:

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

Talvez queiramos até mesmo nos livrar de coisas desnecessárias:

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