R:xts 时间戳与实际数据时间戳相差 1 毫秒
R: xts timestamp differ from real data timestamp by 1 millisecond
所以我有以下数据。
tt <- structure(list(Timestamp = c("2018-03-01 09:51:59.969", "2018-03-01 09:51:59.969",
"2018-03-01 09:51:59.970", "2018-03-01 09:51:59.971", "2018-03-01 09:51:59.987",
"2018-03-01 09:51:59.988"), Mid_Px = c(30755.5, 30755, 30755.5,
30756, 30756.5, 30756.5)), .Names = c("Timestamp", "Mid_Px"), class = "data.frame", row.names = 85774:85779)
看起来像这样:
Timestamp Mid_Px
85774 2018-03-01 09:51:59.969 30755.5
85775 2018-03-01 09:51:59.969 30755.0
85776 2018-03-01 09:51:59.970 30755.5
85777 2018-03-01 09:51:59.971 30756.0
85778 2018-03-01 09:51:59.987 30756.5
85779 2018-03-01 09:51:59.988 30756.5
当我尝试使用下面的代码从中创建一个 xts 对象时,事情开始变糟。
tt_ts <- strptime(tt[,1],"%Y-%m-%d %H:%M:%OS")
tt_ts
[1] "2018-03-01 09:51:59.969 CST" "2018-03-01 09:51:59.969 CST" "2018-03-01 09:51:59.970 CST" "2018-03-01 09:51:59.971 CST" "2018-03-01 09:51:59.987 CST"
[6] "2018-03-01 09:51:59.988 CST"
xts(x=tt[,c(-1)], order.by=tt_ts)
[,1]
2018-03-01 09:51:59.969 30755.5
2018-03-01 09:51:59.969 30755.0
2018-03-01 09:51:59.970 30755.5
2018-03-01 09:51:59.970 30756.0
2018-03-01 09:51:59.986 30756.5
2018-03-01 09:51:59.987 30756.5
请注意第 4,5 行和第 6 行中的毫秒数不正确。
我做错了什么?我怎样才能修复它以显示正确的时间戳?
这类似于R issue with rounding milliseconds。一种简单的解决方案是按照那里的建议添加 0.5 毫秒:
tt_ts <- strptime(tt[,1],"%Y-%m-%d %H:%M:%OS") + 0.0005
xts::xts(x=tt[,c(-1)], order.by=tt_ts)
# [,1]
# 2018-03-01 09:51:59.969 30755.5
# 2018-03-01 09:51:59.969 30755.0
# 2018-03-01 09:51:59.970 30755.5
# 2018-03-01 09:51:59.971 30756.0
# 2018-03-01 09:51:59.987 30756.5
# 2018-03-01 09:51:59.988 30756.5
我们可以从一个简单的例子看出这一点:
st <- strptime("2018-03-01 09:51:59.971", "%Y-%m-%d %H:%M:%OS")
format(st, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.971"
pt <- as.POSIXct(st)
format(pt, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.970"
转换为POSIXct
后ms错误。提高输出精度,我们看到用于表示时间的浮点数刚好低于所需值,但 R 截断了数字而不是四舍五入:
format(pt, "%Y-%m-%d %H:%M:%OS6")
#> [1] "2018-03-01 09:51:59.970999"
移动所需精度的一半可以解决此问题。
format(pt + 0.0005, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.971"
一般来说,如果x是一个小数点后3位的数字,开区间内的任意数字(x - 0.0005, x + 0.0005) 将四舍五入为 x。在截断时,这仍然适用于 [x, x + 0.0005) 内的那些。但是 (x - 0.0005, x) 内的那些将由 x - 0.001 表示,如您观察到的.如果我们在截断之前将相关数字移动 0.0005,我们就是在谈论范围 (x, x + 0.001)。所有这些数字都将根据需要截断为 x。
我排除了x ± 0.0005 因为四舍五入的规则不同,代表时间点的实际浮点数会比这个更接近期望值。
编辑:关于评论中关于采取差异的问题:如果将它添加到两个点,是否添加半毫秒并不重要。时间点需要自行调整的示例:
st1 <- strptime("2018-03-01 09:51:59.971", "%Y-%m-%d %H:%M:%OS")
format(st1, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.970"
pt1 <- as.POSIXct(st1)
format(pt1, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.970"
format(pt1 + 0.0005, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.971"
以及不需要调整的时间点:
st2 <- strptime("2018-03-01 09:51:59.969", "%Y-%m-%d %H:%M:%OS")
format(st2, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.969"
pt2 <- as.POSIXct(st2)
format(pt2, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.969"
format(pt2 + 0.0005, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.969"
差异是相同的,独立于任何调整:
difftime(pt1, pt2, "secs")
#> Time difference of 0.001999855 secs
difftime(pt1 + 0.0005, pt2 + 0.0005, "secs")
#> Time difference of 0.001999855 secs
所以我有以下数据。
tt <- structure(list(Timestamp = c("2018-03-01 09:51:59.969", "2018-03-01 09:51:59.969",
"2018-03-01 09:51:59.970", "2018-03-01 09:51:59.971", "2018-03-01 09:51:59.987",
"2018-03-01 09:51:59.988"), Mid_Px = c(30755.5, 30755, 30755.5,
30756, 30756.5, 30756.5)), .Names = c("Timestamp", "Mid_Px"), class = "data.frame", row.names = 85774:85779)
看起来像这样:
Timestamp Mid_Px
85774 2018-03-01 09:51:59.969 30755.5
85775 2018-03-01 09:51:59.969 30755.0
85776 2018-03-01 09:51:59.970 30755.5
85777 2018-03-01 09:51:59.971 30756.0
85778 2018-03-01 09:51:59.987 30756.5
85779 2018-03-01 09:51:59.988 30756.5
当我尝试使用下面的代码从中创建一个 xts 对象时,事情开始变糟。
tt_ts <- strptime(tt[,1],"%Y-%m-%d %H:%M:%OS")
tt_ts
[1] "2018-03-01 09:51:59.969 CST" "2018-03-01 09:51:59.969 CST" "2018-03-01 09:51:59.970 CST" "2018-03-01 09:51:59.971 CST" "2018-03-01 09:51:59.987 CST"
[6] "2018-03-01 09:51:59.988 CST"
xts(x=tt[,c(-1)], order.by=tt_ts)
[,1]
2018-03-01 09:51:59.969 30755.5
2018-03-01 09:51:59.969 30755.0
2018-03-01 09:51:59.970 30755.5
2018-03-01 09:51:59.970 30756.0
2018-03-01 09:51:59.986 30756.5
2018-03-01 09:51:59.987 30756.5
请注意第 4,5 行和第 6 行中的毫秒数不正确。
我做错了什么?我怎样才能修复它以显示正确的时间戳?
这类似于R issue with rounding milliseconds。一种简单的解决方案是按照那里的建议添加 0.5 毫秒:
tt_ts <- strptime(tt[,1],"%Y-%m-%d %H:%M:%OS") + 0.0005
xts::xts(x=tt[,c(-1)], order.by=tt_ts)
# [,1]
# 2018-03-01 09:51:59.969 30755.5
# 2018-03-01 09:51:59.969 30755.0
# 2018-03-01 09:51:59.970 30755.5
# 2018-03-01 09:51:59.971 30756.0
# 2018-03-01 09:51:59.987 30756.5
# 2018-03-01 09:51:59.988 30756.5
我们可以从一个简单的例子看出这一点:
st <- strptime("2018-03-01 09:51:59.971", "%Y-%m-%d %H:%M:%OS")
format(st, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.971"
pt <- as.POSIXct(st)
format(pt, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.970"
转换为POSIXct
后ms错误。提高输出精度,我们看到用于表示时间的浮点数刚好低于所需值,但 R 截断了数字而不是四舍五入:
format(pt, "%Y-%m-%d %H:%M:%OS6")
#> [1] "2018-03-01 09:51:59.970999"
移动所需精度的一半可以解决此问题。
format(pt + 0.0005, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.971"
一般来说,如果x是一个小数点后3位的数字,开区间内的任意数字(x - 0.0005, x + 0.0005) 将四舍五入为 x。在截断时,这仍然适用于 [x, x + 0.0005) 内的那些。但是 (x - 0.0005, x) 内的那些将由 x - 0.001 表示,如您观察到的.如果我们在截断之前将相关数字移动 0.0005,我们就是在谈论范围 (x, x + 0.001)。所有这些数字都将根据需要截断为 x。
我排除了x ± 0.0005 因为四舍五入的规则不同,代表时间点的实际浮点数会比这个更接近期望值。
编辑:关于评论中关于采取差异的问题:如果将它添加到两个点,是否添加半毫秒并不重要。时间点需要自行调整的示例:
st1 <- strptime("2018-03-01 09:51:59.971", "%Y-%m-%d %H:%M:%OS")
format(st1, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.970"
pt1 <- as.POSIXct(st1)
format(pt1, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.970"
format(pt1 + 0.0005, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.971"
以及不需要调整的时间点:
st2 <- strptime("2018-03-01 09:51:59.969", "%Y-%m-%d %H:%M:%OS")
format(st2, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.969"
pt2 <- as.POSIXct(st2)
format(pt2, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.969"
format(pt2 + 0.0005, "%Y-%m-%d %H:%M:%OS3")
#> [1] "2018-03-01 09:51:59.969"
差异是相同的,独立于任何调整:
difftime(pt1, pt2, "secs")
#> Time difference of 0.001999855 secs
difftime(pt1 + 0.0005, pt2 + 0.0005, "secs")
#> Time difference of 0.001999855 secs