2012-06-07 26 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"ようなステートメントを使用することはないことに気付きました正確な桁数をピックアップするようです。

私が使用しているバージョンは、Windowsで32ビット2.15.0であるが、これは私の元のデータは、私が見つけなければならないCSVファイル内でこれらの日付時刻文字列であることをR.

のための他の状況注下に存在しているようですそれを文字列から正しいミリ秒の時間に変換する方法。

+1

ここでformat()を使用する必要はなく、気を散らす。 。 。 – 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" 

"%OSn"フォーマット文字列で

> 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 

、1つの軍の切り捨て

で。小数第2位を浮動小数点で正確に表すことができない場合、切り捨ては間違った方向に進む可能性があります。あなたは物事が間違った方向に行く表示された場合、あなたはまた、あなたがしたいユニットに明示的に丸めるか、(場合に 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ビットシステムを持っていません。私は自分の答えを更新しました。 '' POSIXlt ''オブジェクトとして取得した後に、あなたの時間に小さな部分(あなたの場合は0.0005)を追加して、それが状況を改善するかどうかを確認してください。詳細は、R-Develスレッドを参照してください。 –

+1

私は再現できます - 私は32ビットと64ビットの両方をWin7 64ビットシステムにインストールしました。問題は32bit 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を呼び出します)の動作ではありません。あなたが見てする必要がありますので、POSIXltリストの各要素は、個別に構築format.POSIXltフォーマット:あなたは56.060を見るよう

print(x$sec, digits=20) 
[1] 56.060999999999999943 

そして、その数は、小数点以下第3位で切り捨てられます。あなたは直接formatを呼び出すことで、これを見ることができます:私は、この問題はまだ32ビットR 3.01のために、これはの32ビットの実装に固有の浮動小数点データの切り捨てに起因することが存在することに注目したテストで

> format(x, "%H:%M:%OS6") 
[1] "13:29:56.060999" 
1

POSIXltの日付時刻のためのprint、format、およびas.character演算子。

下位のデータは、1つのケース(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))) 
    }