gpt4 book ai didi

r - 在日期操作中避免舍入陷阱的最佳实践

转载 作者:行者123 更新时间:2023-12-03 14:18:55 26 4
gpt4 key购买 nike

我正在做一些日期/时间操作,并在转换 date -> time -> date 时遇到可解释但令人不快的往返问题。我通过在适当的点四舍五入暂时克服了这个问题,但我想知道是否有更清洁的日期处理最佳实践。我正在混合使用 base-R 和 lubridate职能。

tl;博士有没有一种简单的方法可以将十进制日期 (YYYY.fff) 转换为 Date类(和返回)而不通过 POSIXt 并导致四舍五入(和潜在的时区)并发症?

从 1918 年的几天开始,作为单独的年/月/日列(不是我的问题的关键部分,但它是我的管道恰好开始的地方):

library(lubridate)
dd <- data.frame(year=1918,month=9,day=1:12)

转换年/月/日 -> 日期 -> 时间:
dd <- transform(dd,
time=decimal_date(make_date(year, month, day)))

结果时间向量中的连续差异 由于舍入 不完全为 1 : 这是可以理解的,但会导致问题。
table(diff(dd$time)*365)
## 0.999999999985448 1.00000000006844
## 9 2

现在假设我转换回一个日期:日期在午夜之前或之后(在任一方向上相差 <1 秒):
d2 <- lubridate::date_decimal(dd$time)
# [1] "1918-09-01 00:00:00 UTC" "1918-09-02 00:00:00 UTC"
# [3] "1918-09-03 00:00:00 UTC" "1918-09-03 23:59:59 UTC"
# [5] "1918-09-04 23:59:59 UTC" "1918-09-05 23:59:59 UTC"
# [7] "1918-09-07 00:00:00 UTC" "1918-09-08 00:00:00 UTC"
# [9] "1918-09-09 00:00:00 UTC" "1918-09-09 23:59:59 UTC"
# [11] "1918-09-10 23:59:59 UTC" "1918-09-12 00:00:00 UTC"

如果我现在想要日期(而不是 POSIXct 对象),我可以使用 as.Date() ,但令我沮丧的是 as.Date() 截断而不是舍入 ...
tt <- as.Date(d2)
## [1] "1918-09-01" "1918-09-02" "1918-09-03" "1918-09-03" "1918-09-04"
## [6] "1918-09-05" "1918-09-07" "1918-09-08" "1918-09-09" "1918-09-09"
##[11] "1918-09-10" "1918-09-12"

所以现在的差异是 0/1/2 天:
table(diff(tt))
# 0 1 2
# 2 7 2

我可以通过先四舍五入来解决这个问题:
table(diff(as.Date(round(d2))))
## 1
## 11

但我想知道是否有更好的方法(例如,将 POSIXct 排除在我的管道之外并保留日期......

正如 this R-help desk article from 2004 所建议的那样格洛腾迪克和 Petzoldt:

When considering which class to use, always choose the least complex class that will support the application. That is, use Date if possible, otherwise use chron and otherwise use the POSIX classes. Such a strategy will greatly reduce the potential for error and increase the reliability of your application.



本文中的扩展表显示了如何在 Date 之间进行转换。 , chron , 和 POSIXct ,但不包括作为候选人之一的十进制时间......

最佳答案

如果可能的话,似乎最好避免从十进制时间转换回来。

从日期转换为十进制日期时,还需要考虑时间。由于Date没有与之关联的特定时间,decimal_date固有地假定它是 00:00:00 .

然而,如果我们只关心日期(而不是时间),我们可以假设时间是任何东西。可以说,一天的中间(12:00:00)和一天的开始(00:00:00)一样好。这将使转换回 Date更可靠,因为我们不在午夜标记并且几秒钟的关闭不会影响输出。一种方法是添加 12*60*60/(365*24*60*60)dd$time

dd$time2 = dd$time + 12*60*60/(365*24*60*60)
data.frame(dd[1:3],
"00:00:00" = as.Date(date_decimal(dd$time)),
"12:00:00" = as.Date(date_decimal(dd$time2)),
check.names = FALSE)
# year month day 00:00:00 12:00:00
#1 1918 9 1 1918-09-01 1918-09-01
#2 1918 9 2 1918-09-02 1918-09-02
#3 1918 9 3 1918-09-03 1918-09-03
#4 1918 9 4 1918-09-03 1918-09-04
#5 1918 9 5 1918-09-04 1918-09-05
#6 1918 9 6 1918-09-05 1918-09-06
#7 1918 9 7 1918-09-07 1918-09-07
#8 1918 9 8 1918-09-08 1918-09-08
#9 1918 9 9 1918-09-09 1918-09-09
#10 1918 9 10 1918-09-09 1918-09-10
#11 1918 9 11 1918-09-10 1918-09-11
#12 1918 9 12 1918-09-12 1918-09-12

It should be noted, however, that the value of decimal time obtained in this way will be different.

关于r - 在日期操作中避免舍入陷阱的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47422773/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com