Tentukan format Tanggal kustom untuk argumen colClasses di read.table / read.csv

101

Pertanyaan:

Apakah ada cara untuk menentukan format Tanggal saat menggunakan argumen colClasses di read.table / read.csv?

(Saya menyadari bahwa saya dapat mengonversi setelah mengimpor, tetapi dengan banyak kolom tanggal seperti ini, akan lebih mudah melakukannya di langkah impor)


Contoh:

Saya memiliki .csv dengan kolom tanggal dalam format %d/%m/%Y.

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

Ini membuat konversi salah. Misalnya, 15/07/2008menjadi 0015-07-20.


Kode yang dapat direproduksi:

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

Dan seperti inilah hasilnya:

keluaran kode

Tommy O'Dell
sumber
Cara hackish untuk melakukan ini adalah dengan membuat versi Anda sendiri read.tabledan menambahkan formatargumen yang diteruskan ke as.Date. Saya tidak akan terkejut jika ada cara yang lebih baik yang tidak saya pikirkan.
joran

Jawaban:

158

Anda dapat menulis fungsi Anda sendiri yang menerima string dan mengubahnya menjadi Tanggal menggunakan format yang Anda inginkan, lalu gunakan setAsuntuk menyetelnya sebagai asmetode. Kemudian Anda dapat menggunakan fungsi Anda sebagai bagian dari colClasses.

Mencoba:

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)

Kemudian ubah jika perlu untuk mengerjakan data Anda.

Edit ---

Anda mungkin ingin menjalankannya setClass('myDate')terlebih dahulu untuk menghindari peringatan tersebut (Anda dapat mengabaikan peringatan tersebut, tetapi dapat mengganggu jika Anda sering melakukan ini dan ini adalah panggilan sederhana yang menghilangkannya).

Greg Snow
sumber
2
Wow - setAs adalah penyelamat! Bagaimana saya belum pernah melihat fungsi ini sebelumnya?
pengguna295691
4
Perhatikan bahwa Anda mungkin mendapatkan peringatan 'tanpa definisi untuk kelas "myDate"' seperti yang dijelaskan dalam pertanyaan ini .
Danny D'Amours
1
Apa yang setMethod('myDate')harus dilakukan? Menjalankannya hanya memberi saya kesalahan ...
Josh O'Brien
1
@ JoshO'Brien, maaf itu seharusnya sudah setClass(diperbaiki sekarang). Apa yang dilakukannya adalah mencegah setAsdikeluarkannya peringatan tentang 'myDate' tidak ada sebagai kelas. Peringatan itu tidak berbahaya dan semuanya masih berfungsi, tetapi menyetel kelas berarti Anda bahkan tidak melihat peringatan itu.
Greg Snow
1
@MySchizoBuddy, Jika Anda hanya memiliki satu kolom tanggal dan Anda melakukan ini satu kali maka mungkin tidak masalah cara Anda melakukannya. Tetapi jika Anda memiliki beberapa kolom dalam kumpulan data Anda yang merupakan tanggal, maka saya pikir pendekatan ini mungkin akan lebih sederhana daripada mengubah setiap kolom setelah membaca.
Greg Snow
25

Jika hanya ada 1 format tanggal yang ingin Anda ubah, Anda dapat menggunakan Defaultspaket untuk mengubah format default di dalamnyaas.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" ...

Saya pikir jawaban @Greg Snow jauh lebih baik, karena tidak mengubah perilaku default dari fungsi yang sering digunakan.

mnel
sumber
7

Jika Anda membutuhkan waktu juga:

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

Dahulu kala, sementara itu masalah telah diselesaikan oleh Hadley Wickham. Jadi saat ini solusinya direduksi menjadi satu langkah:

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

Mungkin kita bahkan ingin menyingkirkan hal-hal yang tidak perlu:

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