将 7 位或 8 位数字转换为 R 中的日期

Converting 7 or 8 digit numbers to dates in R

我正在将一个非常大的固定宽度数据集导入 R 并希望使用 vroom 以获得更快的速度。但是,此数据集中的日期采用 7 位或 8 位数字格式,具体取决于月份中的日期是 1 位还是 2 位(示例如下)。

#8 digit date (1985-03-21):
#  21031985
#7 digit date (1985-03-01):
#  1031985

我看不出有任何方法可以像通常那样使用 col_date(format = ) 来指定这种类型的格式。制作一个将这些 7/8 位数字转换为日期的函数很容易,但这样做意味着要具体化导入的数据并消除 vroom 提供的速度优势。

我正在寻找一种方法让 vroom 自行解释这些数字,或者寻找一种不会牺牲 vroom 速度的解决方法。

非常感谢您的帮助。

这些格式通常很糟糕,但无论如何我都不认为 readr 中的任何内容都适合您,因为 1 位或 2 位数字 day-of-month。我建议将该列导入为 col_character,然后将它们 post-processing 和

vec <- c("21031985", "1031985")
as.Date(paste0(strrep("0", pmax(8 - nchar(vec), 0)), vec), format = "%d%m%Y")
# [1] "1985-03-21" "1985-03-01"

快 walk-through:

  • 8 - nchar(vec)告诉我们每个字符串的左边需要填充多少个0。在这种情况下,它应该分别是 01。如果你有长度为 6 的字符串,这 可能 是个问题,只有你知道这是否是个问题。

  • strrep("0", ..) 根据需要多次重复 0 字符串,包括 strrep("0", 0) 生成 ""(无零)。

  • pmax(.., 0) 是防御型程序员,如果里面有一个长度为 9 的字符串,我们不能做 strrep("0", -1),我们要防止它变成负数。

  • paste0(.., vec) 进行实际填充。

从那里开始,所有字符串都应该被规范化并且能够使用 "%d%m%Y" 进行转换。

如果您有整数数据,您可以将丢失的 0s 重新填充。

as.Date(sprintf("%08d", vec), format = "%d%m%Y")
# [1] "1985-03-21" "1985-03-01"

Vroom 可以使用管道作为输入。这意味着您可以使用 awk 之类的工具来修复格式(例如,使其始终为 8 位数字,这很容易使用 sprintf)。这样您仍然可以从 vroom 流式传输文件中受益。您甚至可以使用 R - 但如果您追求性能,则需要能够处理文件流并且最好是轻量级的东西。

我用了一个测试文件test.csv:

id,date,text
1,1022020,some
2,12042020,more
3,2012020,text

我可以通过阅读它(当然 awk 调用需要根据您的数据进行调整 - 但本质上,如果您只需要调整列 </code> 表示第二列,则 <code>',' 指定分隔符):

vroom(pipe("awk -F ',' 'BEGIN{OFS=\",\"}; NR==1{print}; NR!=1 {=sprintf(\"%08d\",);print;}' test.csv"),
      col_types=cols(date=col_date(format='%d%m%Y'))
)

给予

# A tibble: 3 × 3
     id date       text
  <int> <date>     <chr>
1     1 2020-02-01 some
2     2 2020-04-12 more
3     3 2020-01-02 text