R - 如何格式化 datatable/dataframe 中多列的日期

R - How to format the date of several columns in a datatable/dataframe

我想使用 lubridatecolumn indexing 格式化 datatable/dataframe 中的多个列。

假设有一个非常大的数据集,其中有几个未格式化的date列。问题是我如何识别这些列(最有可能通过索引),然后使用 lubridate.

在一个脚本中同时格式化它们
library(data.table)
library (lubridate) 

> dt <- data.frame(date1 = c("14.01.2009", "9/2/2005",  "24/1/2010", "28.01.2014"),var1 = rnorm(4,2,1), date2 = c("09.01.2009", "23/8/2005","17.01.2000", "04.01.2005"))
> dt
       date1     var1      date2
1 14.01.2009 2.919293 09.01.2009
2   9/2/2005 2.390123  23/8/2005
3  24/1/2010 0.878209 17.01.2000
4 28.01.2014 2.224461 04.01.2005

dt <- setDT(dt)

我试过这些:

> dmy(dt$date1,dt$date2)# his dose not generate two columns
[1] "2009-01-14" "2005-02-09" "2010-01-24" "2014-01-28" "2009-01-09" "2005-08-23"
[7] "2000-01-17" "2005-01-04"

> as.data.frame(dmy(dt$date1,dt$date2)) 
  dmy(dt$date1, dt$date2) # this dose not generate two columns either  
1              2009-01-14
2              2005-02-09
3              2010-01-24
4              2014-01-28
5              2009-01-09
6              2005-08-23
7              2000-01-17
8              2005-01-04


dmy(dt[,.SD, .SD =c(1,3)])
[1] NA NA

> sapply(dmy(dt$date1,dt$date2),dmy)
[1] NA NA NA NA NA NA NA NA
Warning messages:
1: All formats failed to parse. No formats found. 

非常感谢任何帮助。

怎么样:

dt <- data.frame(date1 = c("14.01.2009", "9/2/2005",  "24/1/2010", "28.01.2014"),var1 = rnorm(4,2,1), date2 = c("09.01.2009", "23/8/2005","17.01.2000", "04.01.2005"))

for(i in c(1,3)){
     dt[,i] <- dmy(dt[,i])
}

这里有一个 data.table 方法。假设您有 k 列名为 dateX:

k = 2
date_cols = paste0('date', 1:k)
for (col in date_cols) {
    set(dt, j=col, value=dmy(dt[[col]])
}

你可以避免循环,但显然循环可能更快;见 this answer

dt[,(date_cols) := lapply(.SD, dmy), .SDcols=date_cols]

编辑

如果你有任意列名,假设数据看起来像 OP

date_cols = names(dt)[grep("^\d{4}(\.|/)", names(dt))]
date_cols = c(date_cols, names(dt)[grep("(\.|/)\d{4}", names(dt))])

如果分隔符的数量多于 ./,您可以添加正则表达式,并且您可以将其组合成一个 grep,但这对我来说更清楚。

远非完美,这是一个应该更通用的解决方案:

此处唯一的假设是,日期列包含由 ./- 分隔的数字。如果有其他分隔符,可以添加它们。但是如果你有另一个类似的变量,但不是日期,这将无法正常工作。

for (j in seq_along(dt)) if (all(grepl('\d+(\.|/|-)\d+(\.|/|-)\d+',dt[,j]))) dt[,j] <- dmy(dt[,j])

这遍历列并使用正则表达式检查日期是否存在。如果是这样,它会将其转换为日期并覆盖该列。

使用data.table:

for (j in seg_along(dt)) if (all(grepl('\d+(\.|/|-)\d+(\.|/|-)\d+',dt[,j]))) set(dt,j = j, value = dmy(dt[[j]]))

您也可以将 all 替换为 any,如果您在该列中有任何匹配项,您可以假设该列中的所有值都是可以读取的日期dmy.