Вкажіть спеціальний формат дати для аргументу colClasses у read.table / read.csv


101

Питання:

Чи є спосіб визначити формат дати при використанні аргументу colClasses у read.table / read.csv?

(Я розумію, що я можу конвертувати після імпорту, але з такою кількістю стовпців дат, як це, було б простіше зробити це на етапі імпорту)


Приклад:

У мене є .csv із стовпцями дати у форматі %d/%m/%Y.

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

Це отримує конверсію неправильно. Наприклад, 15/07/2008стає 0015-07-20.


Код, що відтворюється:

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

А ось як виглядає вихід:

вихід коду


Хакейним способом зробити це було б створити власну версію read.tableта додати formatаргумент, який передається as.Date. Я не був би здивований, якщо є кращий спосіб, про який я не думаю.
joran

Відповіді:


158

Ви можете записати власну функцію, яка приймає рядок і перетворює її на Дату, використовуючи потрібний формат, а потім використовувати setAsдля встановлення її як asметоду. Тоді ви можете використовувати свою функцію як частину colClasses.

Спробуйте:

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)

Потім змініть, якщо потрібно, для роботи над вашими даними.

Редагувати ---

Ви можете запустити setClass('myDate')перший, щоб уникнути попередження (ви можете проігнорувати попередження, але воно може набриднути, якщо ви це зробите багато, і це простий дзвінок, який позбавляється від нього).


2
Нічого собі - setAs - рятівник! Як я ніколи раніше не бачив цієї функції?
користувач295691

4
Зауважте, що ви можете отримати попередження "без визначення для класу" myDate "', як це детально описано в цьому запитанні .
Danny D'Amours

1
Що setMethod('myDate')робити? Запуск цього просто дає мені помилку ...
Josh O'Brien

1
@ JoshO'Brien, вибачте, що це мало бути setClassвиправлено зараз. Що це робить, це запобігти setAsнадсилати попередження про те, що "myDate" не існує як клас. Попередження нешкідливо, і все ще працює, але встановлення класу означає, що ви навіть не бачите попередження.
Грег Сног

1
@MySchizoBuddy, Якщо у вас є лише один стовпець дати, і ви робите це одноразово, то, мабуть, не має значення, яким саме способом це зробити. Але якщо у вашому наборі даних є кілька стовпців, які є датами, я думаю, такий підхід, ймовірно, буде простішим, ніж зміна кожної колонки після читання.
Грег Сніг

25

Якщо ви бажаєте змінити лише один формат дати, ви можете використовувати Defaultsпакет, щоб змінити формат за замовчуванням в межахas.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" ...

Я думаю, що відповідь @Greg Snow набагато краща, оскільки це не змінює поведінку часто використовуваної функції за замовчуванням.


7

Якщо вам також потрібен час:

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

Давно, тим часом, проблему вирішив Едлі Вікхем. Тож сьогодні рішення зводиться до онлінера:

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

Можливо, ми хочемо навіть позбутися зайвих речей:

data <- as.data.frame(data)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.