как преобразовать все значения даты и времени в столбце фрейма данных в определенный формат даты и времени в R (когда файл csv сохранил их в разных форматах)

Это может показаться глупым вопросом, но я потратил дни на то, чтобы сначала определить, в чем проблема, а теперь пытаюсь ее решить!

У меня есть фрейм данных со столбцом, заполненным датой и временем. Этот кадр данных является продуктом множества различных шагов обработки, примененных к ряду отдельных файлов, которые в какой-то момент были объединены в один файл (люди идентифицируются столбцом идентификатора). Поскольку в какой-то момент файлы должны были обрабатываться по-разному, формат столбца даты и времени различается между блоками уникальных идентификаторов, т. е. некоторые ячейки имеют формат «%Y-%m-%d %H:%M:%S» и некоторые имеют формат «%d/%m/%Y %H:%M:%S», хотя все они выглядят так, как будто они во втором из двух форматов, когда я открываю файл csv.

Я хочу загрузить данные и разделить их по уникальным значениям идентификатора, прежде чем делать с ними кучу других вещей на основе столбца даты и времени. К сожалению, независимо от того, что я пытаюсь сделать, все данные не будут приведены к одному типу формата даты и времени. Я попытался переформатировать столбец в исходном файле csv или загрузить данные и переклассифицировать их как объект POSIXct с одним форматом, но когда я делаю это, эти блоки идентификаторов в формате, который я не указываю с помощью команды POSIXct, возвращаются как НС (очевидно!). Я также попытался преобразовать данные в числовой формат. Ничто из того, что я пытаюсь, не работает, и мой фрейм данных слишком велик, чтобы проходить каждый блок идентификатора отдельно! Должен быть способ сделать это, и он должен быть простым! Пожалуйста, кто-нибудь, избавьте меня от моих страданий! Большое спасибо.

Пример данных:

> dput(t)

  row_id            datetime id
1 165656 09/02/2017 15:50:55  1
2 165657 09/02/2017 15:51:25  1
3 165658 09/02/2017 15:51:55  1
4 165659 09/02/2017 15:52:25  1
5 165660 09/02/2017 15:52:55  1
6 165661 2017-02-09 15:53:25  2
7 165662 2017-02-09 15:53:55  2
8 165663 2017-02-09 15:54:25  2
9 165664 2017-02-09 15:54:55  2

Я пробовал следующее в обоих форматах даты и времени (оба из которых работают только для одного из двух):

>t$datetime = as.POSIXct(strptime(t$datetime, format="%Y-%m-%d %H:%M:%S"), tz="UTC")
>t$datetime
[1] NA                        NA                        NA                       
[4] NA                        NA                        "2017-02-09 15:53:25 UTC"
[7] "2017-02-09 15:53:55 UTC" "2017-02-09 15:54:25 UTC" "2017-02-09 15:54:55 UTC"

>t$datetime = unclass(as.POSIXct(strptime(t$datetime, "%Y-%m-%d %H:%M:%S"))) 

person jjulip    schedule 19.09.2019    source источник


Ответы (2)


Мы можем использовать parse_date_time из lubridate и указать различные форматы данных.

library(lubridate)
df$datetime <- parse_date_time(df$datetime,c("%d/%m/%Y %T", "%Y-%m-%d %T"))
df$datetime

#[1] "2017-02-09 15:50:55 UTC" "2017-02-09 15:51:25 UTC" "2017-02-09 15:51:55 UTC"
#[4] "2017-02-09 15:52:25 UTC" "2017-02-09 15:52:55 UTC" "2017-02-09 15:53:25 UTC"
#[7] "2017-02-09 15:53:55 UTC" "2017-02-09 15:54:25 UTC" "2017-02-09 15:54:55 UTC"

class(df$datetime)
#[1] "POSIXct" "POSIXt" 

данные

df <- structure(list(row_id = structure(1:9, .Label = c("1 165656", 
"2 165657", "3 165658", "4 165659", "5 165660", "6 165661", "7 165662", 
"8 165663", "9 165664"), class = "factor"), datetime = structure(1:9,
.Label = c("09/02/2017 15:50:55", "09/02/2017 15:51:25", "09/02/2017 15:51:55", 
"09/02/2017 15:52:25", "09/02/2017 15:52:55", "2017-02-09 15:53:25", 
"2017-02-09 15:53:55", "2017-02-09 15:54:25", "2017-02-09 15:54:55"), 
class = "factor"), id = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L)), 
class = "data.frame", row.names = c(NA, -9L))
person Ronak Shah    schedule 19.09.2019
comment
Второй аргумент parse_date_time можно сократить до c("dmYT", "YmdT"). - person G. Grothendieck; 19.09.2019
comment
Спасибо-ооооооооооооооооооооооооочень большое! Вы даже не представляете, насколько вы только что улучшили мой день (и выходные!) - person jjulip; 19.09.2019

Вы можете использовать ifelse в сочетании с grepl для проверки определенной маски формата даты перед вызовом as.POSIXct:

t$dt <- ifelse(grepl("\\d{2}/\\d{2}/\\d{4} \\d{2}:\\d{2}:\\d{2}", t$datetime),
               as.POSIXct(strptime(t$datetime, "%d/%m/%Y %H:%M:%S")),
               as.POSIXct(strptime(t$datetime, "%Y-%m-%d %H:%M:%S")))

Это предполагает, что у вас есть только два формата даты. Если бы их могло быть там или больше, нам пришлось бы изменить приведенное выше решение, чтобы принять это во внимание.

Вот некоторые примеры данных, чтобы показать, что это можно заставить работать:

t <- data.frame(datetime=c("09/02/2017 15:50:55", "2017-02-09 15:50:55"))
t$dt <- ifelse(grepl("\\d{2}/\\d{2}/\\d{4} \\d{2}:\\d{2}:\\d{2}", t$datetime),
               as.POSIXct(strptime(t$datetime, "%d/%m/%Y %H:%M:%S")),
               as.POSIXct(strptime(t$datetime, "%Y-%m-%d %H:%M:%S")))
t

             datetime         dt
1 09/02/2017 15:50:55 1486651855   <-- same values for dt, as expected
2 2017-02-09 15:50:55 1486651855
person Tim Biegeleisen    schedule 19.09.2019
comment
Спасибо Тим! Оценил! - person jjulip; 19.09.2019