2013-04-24 31 views
1

我發現as.POSIXlt有些奇怪的行爲,我無法解釋,我希望別人可以。在調查this question時,我發現有時一秒鐘的小數部分會被不正確地舍入。用微秒舍入誤差使用as.POSIXlt

例如,下面的數字表示從紀元開始以來的一秒鐘,最後6位數字是秒的小數部分,所以第一個數字的秒數應該是.645990。

# Generate sequence of integers to represent date/times 
times <- seq(1366039619645990 , length.out = 11) 
options(scipen=20) 
times 
[1] 1366039619645990 1366039619645991 1366039619645992 1366039619645993 1366039619645994 1366039619645995 
[7] 1366039619645996 1366039619645997 1366039619645998 1366039619645999 1366039619646000 

# Convert to date/time with microseconds 
options(digits.secs = 6) 
as.POSIXlt(times/1e6, tz="EST", origin="1970-01-01") + 5e-7 
[1] "2013-04-15 10:26:59.645990 EST" "2013-04-15 10:26:59.645991 EST" "2013-04-15 10:26:59.645992 EST" 
[4] "2013-04-15 10:26:59.645993 EST" "2013-04-15 10:26:59.645994 EST" "2013-04-15 10:26:59.645995 EST" 
[7] "2013-04-15 10:26:59.645996 EST" "2013-04-15 10:26:59.645997 EST" "2013-04-15 10:26:59.645998 EST" 
[10] "2013-04-15 10:26:59.645999 EST" "2013-04-15 10:26:59.646000 EST" 

我發現我必須添加一個小的增量,等於在時間獲得第二的小數部分的正確表示一半的最小變化,否則會出現舍入誤差。如果我在上面的數字序列上運行as.POSIXlt,但它工作得很好,但是如果我嘗試轉換一個數字,即以.645999結尾的那個數字,那麼截斷的數字將變爲.645,我不知道爲什麼!

# Now just convert the date/time that should end in .645999 
as.POSIXlt(times[10]/1e6, tz="EST", origin="1970-01-01") + 5e-7 
[1] "2013-04-15 10:26:59.645 EST" 

在由as.POSIXlt與所述單個元件等效上述返回的向量比較第十元件。發生什麼事?

會議信息:

R version 2.15.2 (2012-10-26) 
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit) 

locale: 
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8 

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] raster_2.0-41 sp_1.0-5  

loaded via a namespace (and not attached): 
[1] grid_2.15.2  lattice_0.20-13 tools_2.15.2 
+0

在我的機器上,當執行'times/1e6'時,它會刪除'times'的所有小數。事實上,我得到'2013-04-15 10:26:59 EST' 11次... – Michele 2013-04-24 09:23:18

+0

@Michele謝謝! - 你已經向我展示了我在示例中缺少一個重要的代碼 - 現在添加! – 2013-04-24 09:24:14

+0

@Michele請你再試一次嗎?先運行'options(digits.secs = 6)'。 – 2013-04-24 09:25:19

回答

2

這似乎是一個四捨五入的問題,即小數秒的有效數字被丟棄。 冒犯(?)代碼採用POSIXlt類對象的格式方法,即format.POSIXlt,它由print.POSIXlt使用。

如果我們使用下面的兩個值作爲示例,format.POSIXlt使用下面這行代碼來測試小數秒之間差值的絕對值,舍入到連續更大的數字位數。

secs <- c(59.645998 , 59.645999) 
sapply(seq_len(np) - 1L , function(x) abs(secs - round(secs, x))) 
     [,1]  [,2]  [,3]  [,4]  [,5]  [,6] 
[1,] 0.354002 0.045998 0.004002 0.000002 0.000002 0.000002 
[2,] 0.354001 0.045999 0.004001 0.000001 0.000001 0.000001 

正如你可以看到在秒數.xxx999任何舍入到3首或更多個數字給出0.000001影響從而印刷:

# the number of digits used for the fractional seconds is gotten here 
np <- getOption("digits.secs") 

# and the length of digits to be printed is controlled in this loop 
for (i in seq_len(np) - 1L) if (all(abs(secs - round(secs, 
       i)) < 0.000001)) { 
       np <- i 
       break 
      } 

這是因爲0.000001在上述方法中作爲實際找到是:

sprintf("%.20f" , abs(secs[2] - round(secs,5))) 
[1] "0.00000099999999991773"    

# In turn this is used to control the printing of the fractional seconds    
if (np == 0L) 
      "%Y-%m-%d %H:%M:%S" 
     else paste0("%Y-%m-%d %H:%M:%OS", np) 

因此,由於在舍入中使用的測試,小數秒會被截斷爲只有3個小數位。我認爲如果for循環中的測試值設置爲5e-7,則此問題將消失。

當返回的結果是POSIXlt對象的向量時,必須調用不同的打印方法。

1

我沒有得到正確的答案(繼續尋找到它),但我認爲這是有趣:

times <- seq(1366039619645990 , length.out = 11) 
# Convert to date/time wz="EST", origin="1970-01-01") + 5e-7 
options(digits.secs = 6) 

test <- as.POSIXlt(times/1e6, tz="EST", origin="1970-01-01") + 5e-7 

test1[1] <- NULL 
for(i in 1:11) 
    test1[i] <- as.POSIXlt(times[i]/1e6, tz="EST", origin="1970-01-01") + 5e-7 

> identical(test, test1) 
[1] TRUE 

順便說一句,在單個語句,我得到了和你一樣的結果...

> test 
[1] "2013-04-15 10:26:59.645990 EST" "2013-04-15 10:26:59.645991 EST" "2013-04-15 10:26:59.645992 EST" 
[4] "2013-04-15 10:26:59.645993 EST" "2013-04-15 10:26:59.645994 EST" "2013-04-15 10:26:59.645995 EST" 
[7] "2013-04-15 10:26:59.645996 EST" "2013-04-15 10:26:59.645997 EST" "2013-04-15 10:26:59.645998 EST" 
[10] "2013-04-15 10:26:59.645999 EST" "2013-04-15 10:26:59.646000 EST" 
> test[10] 
[1] "2013-04-15 10:26:59.645 EST" 
> as.POSIXlt(times[10]/1e6, tz="EST", origin="1970-01-01") + 5e-7 
[1] "2013-04-15 10:26:59.645 EST" 

看看最後兩條語句,看來這個問題主要是相關的o顯示單個值而不是矢量。但即使在這種情況下,它也可能是截斷,可能是通過floor,而不是四捨五入。

+0

+1讓我看到它必須是舍入或截斷的問題 – 2013-04-24 10:14:46