Как преобразовать различные форматы даты в один формат в нескольких столбцах данных - PullRequest
2 голосов
/ 28 апреля 2020

У меня есть фрейм данных с датами в разных форматах, разбросанных по столбцам, и я хотел бы стандартизировать их в один формат. Я могу выполнить стандартизацию для одного вектора разнородных дат, как в d, определив возможные форматы даты в векторе, например formats, и передав его в as.Date:

d <- c("01-02-2009","01/04/2009","15-Jan-2019", "12-12-2020")
formats <- c("%d-%m-%Y", "%d/%m/%Y", "%d-%b-%Y")
format(as.Date(d, format = formats), "%d-%b-%Y")
[1] "01-Feb-2009" "01-Apr-2009" "15-Jan-2019" "12-Dez-2020"

Но это не работает для фрейма данных:

df <- data.frame(Transaction = c("01-Mar-2015", "31-01-2012", "15/01/1999"), 
                 Delivery = c("01-02-2018", "01/08/2016", "17-09-2007"), 
                 Return = c("27/11/2009", "22-Jan-2013", "20-Nov-1987"))

Здесь стандартизация работает только частично:

df[,1:3] <- lapply(df[,1:3], function(x) format(as.Date(x, format = formats), "%d-%b-%Y"))
df
  Transaction    Delivery      Return
1        <NA> 01-Feb-2018        <NA>
2        <NA> 01-Aug-2016        <NA>
3        <NA>        <NA> 20-Nov-1987

Как даты могут быть стандартизированы в формате %d-%b-%Y в весь фрейм данных?

Ответы [ 2 ]

3 голосов
/ 28 апреля 2020

Проблема в том, что formats в столбцах отличается от уже созданного. Итак, нам нужно что-то вроде

as.Date(df$Transaction, format = c("%d-%b-%Y", "%d-%m-%Y", "%d/%m/%Y"))
#[1] "2015-03-01" "2012-01-31" "1999-01-15"

, то есть formats, указанное в OP, равно

formats
#[1] "%d-%m-%Y" "%d/%m/%Y" "%d-%b-%Y"

, если мы проверим столбец «Транзакция»

df$Transaction
#[1] 01-Mar-2015 31-01-2012  15/01/1999 

Он включает %d-%m-%Y и %d/%m/%Y, который не найден в существующих форматах


Кроме того, для большей ясности переданный вектор format выполняет поэлементное сравнение format

as.Date(df$Transaction, format = c("%d-%b-%Y", "%d/%m/%Y"))
#[1] "2015-03-01" NA           NA   

т.е., передавая "%d/%m/%Y", он должен был соответствовать третьей записи, но поскольку это поэлементное сравнение, он проверяет второй элемент, а затем выполняет повторную обработку вектора формат, поскольку он имеет длину меньше длины столбца «Транзакция»

Это означает, что если наш набор данных состоит из 1e6 строк, он ожидает форматы 1e6, которые должны соответствовать каждому элементу.


или используя anydate из anytime

library(anytime)
addFormats(c('%d-%m-%Y', '%d/%m/%Y'))
df[] <- lapply(df,  function(x) format(anydate(x), "%d-%b-%Y"))
df
#  Transaction    Delivery      Return
#1 01-Mar-2015 01-Feb-2018 27-Nov-2009
#2 31-Jan-2012 01-Aug-2016 22-Jan-2013
#3 15-Jan-1999 17-Sep-2007 20-Nov-1987
3 голосов
/ 28 апреля 2020

С помощью mutate_all вы можете преобразовать все символьные столбцы вашего информационного кадра в один формат даты, используя функцию parse_date_time из lubridate и передавая список форматов в аргументе orders.

Затем вы можете отформатировать эти даты в желаемый результат, используя format:

library(lubridate)
library(dplyr)

formats <- c("%d-%m-%Y", "%d/%m/%Y", "%d-%b-%Y")

df %>% mutate_all( ~parse_date_time(., orders = formats)) %>%
  mutate_all(~format(., "%d-%b-%Y"))

  Transaction    Delivery      Return
1 01-Mar-2015 01-Feb-2018 27-Nov-2009
2 31-Jan-2012 01-Aug-2016 22-Jan-2013
3 15-Jan-1999 17-Sep-2007 20-Nov-1987

Используя apply, вы можете сделать:

library(lubridate)

apply(df, 2, function(x) format(parse_date_time(x, orders = formats), "%d-%b-%Y"))

     Transaction   Delivery      Return       
[1,] "01-Mar-2015" "01-Feb-2018" "27-Nov-2009"
[2,] "31-Jan-2012" "01-Aug-2016" "22-Jan-2013"
[3,] "15-Jan-1999" "17-Sep-2007" "20-Nov-1987"

Отвечает ли он на ваш вопрос?


Примечание: parse_date_time работает на lubridate version 1.7.8. Для lubridate version 1.7.4 вы можете использовать parse_date и заменить orders на format

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...