将 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
。在这种情况下,它应该分别是 0
和 1
。如果你有长度为 6 的字符串,这 可能 是个问题,只有你知道这是否是个问题。
strrep("0", ..)
根据需要多次重复 0
字符串,包括 strrep("0", 0)
生成 ""
(无零)。
pmax(.., 0)
是防御型程序员,如果里面有一个长度为 9 的字符串,我们不能做 strrep("0", -1)
,我们要防止它变成负数。
paste0(.., vec)
进行实际填充。
从那里开始,所有字符串都应该被规范化并且能够使用 "%d%m%Y"
进行转换。
如果您有整数数据,您可以将丢失的 0
s 重新填充。
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
我正在将一个非常大的固定宽度数据集导入 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
。在这种情况下,它应该分别是0
和1
。如果你有长度为 6 的字符串,这 可能 是个问题,只有你知道这是否是个问题。strrep("0", ..)
根据需要多次重复0
字符串,包括strrep("0", 0)
生成""
(无零)。pmax(.., 0)
是防御型程序员,如果里面有一个长度为 9 的字符串,我们不能做strrep("0", -1)
,我们要防止它变成负数。paste0(.., vec)
进行实际填充。
从那里开始,所有字符串都应该被规范化并且能够使用 "%d%m%Y"
进行转换。
如果您有整数数据,您可以将丢失的 0
s 重新填充。
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