考虑到以下问题,在R下舍入毫秒数。如何绕过它以便时间正确?
> options(digits.secs=3)
> as.POSIXlt("13:29:56.061", format='%H:%M:%OS', tz='UTC')
[1] "2012-06-07 13:29:56.060 UTC"
> as.POSIXlt("13:29:56.062", format='%H:%M:%OS', tz='UTC')
[1] "2012-06-07 13:29:56.061 UTC"
> as.POSIXlt("13:29:56.063", format='%H:%M:%OS', tz='UTC')
[1] "2012-06-07 13:29:56.063 UTC"
我注意到此网址提供了背景信息但未解决我的问题: Milliseconds puzzle when calling strptime in R
此网址也涉及此问题,但未解决此问题:R xts: .001 millisecond in index。
在这些情况下,我确实看到以下内容:
> x <- as.POSIXlt("13:29:56.061", format='%H:%M:%OS', tz='UTC')
> print(as.numeric(x), digits=20)
[1] 1339075796.0610001087
网址似乎也表明这只是一个显示问题,但我注意到使用"%OS3"
这样没有选项行的语句似乎没有提取正确的位数。
我在Windows下使用的版本是32位2.15.0,但这似乎存在于R的其他情况下。
请注意,我的原始数据是CSV文件中的这些日期时间字符串我必须找到一种方法,将它们从字符串转换为正确的毫秒时间。
答案 0 :(得分:5)
我没有看到:
> options(digits.secs = 4)
> as.POSIXlt("13:29:56.061", format = '%H:%M:%OS', tz='UTC')
[1] "2012-06-07 13:29:56.061 UTC"
> as.POSIXlt("13:29:56.062", format = '%H:%M:%OS', tz='UTC')
[1] "2012-06-07 13:29:56.062 UTC"
> as.POSIXlt("13:29:56.063", format = '%H:%M:%OS', tz='UTC')
[1] "2012-06-07 13:29:56.063 UTC"
> options(digits.secs = 3)
> as.POSIXlt("13:29:56.061", format = '%H:%M:%OS', tz='UTC')
[1] "2012-06-07 13:29:56.061 UTC"
> as.POSIXlt("13:29:56.062", format = '%H:%M:%OS', tz='UTC')
[1] "2012-06-07 13:29:56.062 UTC"
> as.POSIXlt("13:29:56.063", format = '%H:%M:%OS', tz='UTC')
[1] "2012-06-07 13:29:56.063 UTC"
与
> sessionInfo()
R version 2.15.0 Patched (2012-04-14 r59019)
Platform: x86_64-unknown-linux-gnu (64-bit)
locale:
[1] LC_CTYPE=en_GB.utf8 LC_NUMERIC=C
[3] LC_TIME=en_GB.utf8 LC_COLLATE=en_GB.utf8
[5] LC_MONETARY=en_GB.utf8 LC_MESSAGES=en_GB.utf8
[7] LC_PAPER=C LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_GB.utf8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods
[7] base
使用"%OSn"
格式字符串,强制截断。如果小数秒不能在浮点中精确表示,则截断可能会错误地进行。如果你发现事情出错了,你也可以明确地舍入到你想要的单位,或者添加你希望操作的部分的一半(在显示0.0005
的情况下):
> t1 <- as.POSIXlt("13:29:56.061", format = '%H:%M:%OS', tz='UTC')
> t1
[1] "2012-06-07 13:29:56.061 UTC"
> t1 + 0.0005
[1] "2012-06-07 13:29:56.061 UTC"
(但我说,我在这里看不到问题。)
后一点是Simon Urbanek on the R-Devel mailing list on 30-May-2012。
答案 1 :(得分:3)
这与Milliseconds puzzle when calling strptime in R相同。
你的例子:
> x <- as.POSIXlt("13:29:56.061", format='%H:%M:%OS', tz='UTC')
> print(as.numeric(x), digits=20)
[1] 1339075796.0610001087
不代表问题。 as.numeric(x)
在转换为数字之前将POSIXlt对象转换为POSIXct,因此您会得到不同的浮点精度舍入错误。
print.POSIXlt
(调用format.POSIXlt
)的工作原理并非如此。 format.POSIXlt
分别格式化POSIXlt
列表构造的每个元素,因此您需要查看:
print(x$sec, digits=20)
[1] 56.060999999999999943
该数字在第三个小数位被截断,因此您会看到56.060
。您可以直接致电format
来看到这一点:
> format(x, "%H:%M:%OS6")
[1] "13:29:56.060999"
答案 2 :(得分:2)
在测试中我注意到这个问题仍然存在于32位R 3.01中,这是由于浮点数据的截断是特定于POSIXlt日期时间的打印,格式和as.character运算符的32位实现。
基础数据尚未存储在导致在一种情况下(32位)而不是另一种情况(64位)中截断的不同类型,而是“print”,“format”和“as.character” POSIXlt类型的函数,用于将POSIXlt数据显示为可显示的字符串。
虽然记录的行为是这些函数截断(忽略)额外数字(如@Gavin Simpson所述),但对于32位和64位版本,情况并非如此。展示;我们将生成1000次不同的时间并执行一些比较操作:
> options(digits.sec=3)
> x = as.POSIXlt("13:29:56.061", format='%H:%M:%OS', tz='UTC')
> for (i in 0:999) {
> x[i+1] = as.POSIXlt(paste0("13:29:56.",sprintf("%03d",i)),format='%H:%M:%OS',tz='UTC')
> }
> sum(x[2:1000]>x[1:999])
[1] 999
在32位和64位下,比较运算符是一致的,但是在32位下我看到:
> x[1:6]
[1] "2015-10-16 13:29:56.000 UTC" "2015-10-16 13:29:56.000 UTC"
[3] "2015-10-16 13:29:56.002 UTC" "2015-10-16 13:29:56.003 UTC"
[5] "2015-10-16 13:29:56.003 UTC" "2015-10-16 13:29:56.005 UTC"
所以这显然是一个显示问题。查看POSIXlt数据类型中的实际数字,特别是我们可以看到似乎发生的事情的秒数:
> y = (x[1:6]$sec)
> y
[1] 56.000 56.001 56.002 56.003 56.004 56.005
> trunc(y*1000)/1000
[1] 56.000 56.001 56.002 56.003 56.004 56.005
> trunc((y-floor(y))*1000)/1000
[1] 0.000 0.000 0.002 0.003 0.003 0.005
我建议这是一个应该在底层基础库中修复的错误,作为临时修复,但是你可以覆盖“print”,“as.character”和“format”函数来将输出更改为您想要的输出,例如
format.POSIXlt = function(posix) {
return(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ",
sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec)))
}
print.POSIXlt = function(posix) {
print(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ",
sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec)))
}
as.character.POSIXlt = function(posix) {
return(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ",
sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec)))
}
答案 3 :(得分:1)
毫秒是:
unclass(as.POSIXlt("13:29:56.061", '%H:%M:%OS', tz='UTC'))
$sec
[1] 56.061
...
(这里不需要调用格式,它是参数的名称,而不是其他函数所需的输入)。
否则,我无法重现(在Windows 64位R 2.15.0上):
options(digits.secs = 3)
as.POSIXlt("13:29:56.061", '%H:%M:%OS', tz='UTC')
[1] "2012-06-07 13:29:56.061 UTC"
sessionInfo()
R version 2.15.0 Patched (2012-05-05 r59321)
Platform: x86_64-pc-mingw32/x64 (64-bit)
...