1

説明できない奇妙な振る舞いを見つけ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、上記のように一連の数字で実行すると問題なく動作しますが、1 つの数字、つまり .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"

によって返されるベクトルの 10 番目の要素を、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
4

2 に答える 2

2

これは、小数秒の有効桁数が破棄される丸めの問題のようです。問題のある (?) コードは、クラス のオブジェクトのメソッドの形式にあります。POSIXltつまり、format.POSIXltによって使用されprint.POSIXltます。

以下の 2 つの値を例として使用する場合format.POSIXlt、sapply でラップした次の行を使用して、連続して大きい桁数に丸められた小数秒の差の絶対値をテストします。

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オブジェクトのベクトルである場合、別の印刷メソッドを呼び出す必要があります。

于 2013-04-24T10:13:45.920 に答える