2012-06-07 70 views
5

鑑於R下的舍入毫秒數如下問題,我該如何解決它以便時間正確?與舍入毫秒的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" 

我注意到,這個URL提供了背景信息,但並沒有解決我的問題: Milliseconds puzzle when calling strptime in R

另外這個URL涉及的問題,但並沒有解決它: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 

的URL也似乎表明,這只是一個顯示問題,但我注意到,使用像"%OS3"語句沒有選擇行不似乎取得正確的位數。

我使用的版本是32位2.15.0 Windows下但這似乎在其他情況下,存在對R.

請注意,我的原始數據是一個CSV文件,我必須找到在這些日期時間字符串一種將它們從字符串轉換成正確的毫秒時間的方法。

+1

格式()在這裏的使用是不必要和分散注意力。 。 。 – mdsumner

+0

好的,但我們需要'format ='%H:%M:%OS'。 –

+0

另請參閱http://stackoverflow.com/a/7730759/210673 – Aaron

回答

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作出的。

+0

試用32位版本。 –

+0

@AndrewStern我不能沒有32位系統來試試它。我已經更新了我的答案。嘗試添加一小部分(在你的情況下爲0.0005)到你的時間* *之後,你將它們作爲「POSIXlt」對象,看看是否改善了情況。按照該R-Devel線程獲取更多細節。 –

+1

我可以重現 - 我有一個Win7 64位系統上安裝32位和64位R。看起來問題是特定於32位R. – Fhnuzoag

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) 
... 
+0

當我使用下面的方法對它進行匿名化時,似乎確實是正確的:unclass(as.POSIXlt(「13:29:56.061」,「%H:%M:%OS」,tz ='UTC')),但屏幕當使用as.POSIXlt(「13:29:56.061」,「%H:%M:%OS」,tz ='UTC')時仍然顯示不正確的毫秒數。請注意,我使用的是32位版本,而64位版本可能會更準確,因爲寄存器更大。 –

+1

必須是錯誤的屏幕。 – mdsumner

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(x, "%H:%M:%OS6") 
[1] "13:29:56.060999" 
1

在測試中我已經指出,這個問題仍然存在32位[R 3.01,並認爲這是由於浮點數據的截斷特定於32位實現的:你可以通過調用format直接看到用於POSIXlt日期時間的打印,格式和as.character操作符。

底層數據尚未存儲在導致截斷的一種情況下(32位)而不是另一種(64位),但「打印」,「格式」和「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 

我認爲,這是一個應該被固定在底層基礎庫中的缺陷,作爲一個臨時的解決辦法不過,您可以覆蓋「打印」,「as.character」和「格式」功能以將輸出更改爲所需的輸出,例如

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))) 
    }