2016-09-14 12 views
0

floatが一般的に安全でないため、==を使用しています。しかし、それは下のシナリオでうまくいくのですか?Pythonはどのようにfloat/doubleで動作しますか?

  1. csvファイルA.csvから読み取って、何もせずにデータの前半部分をcsvファイルB.csvに保存します。
  2. A.csvとB.csvの両方から読み取ります。最初の半分のどこでもデータが一致するかどうかを確認するには、==を使用します。

これらはすべてパンダで行われます。 A.csvの列には、datetime、string、およびfloat型があります。明らかに==はdatetimeとstringのために働くので、==がfloatの場合も同様に動作すれば、多くの作業が節約されます。

私のすべてのテストではうまくいくようですが、それはいつもうまくいくと思いますか?

+1

==任意の種類の数字に対して完全に安全です。彼らはどちらかというと等しいか、そうではありません。この問題は、数値をさまざまな表現と比較しているときに発生します。例えば、「2.3」== 2.3は視覚的には同じであっても機能しないかもしれない –

+0

ああ、パンダの部分に注意を払わなかった –

+0

参照http://stackoverflow.com/q/26091689/2800918 – CAB

答えて

3

同じ解析ルーチンを実行すると、同じ文字列表現が同じ浮動体表現になります。浮動小数点の不正確さの問題は、数値に対して数学演算が実行されるとき、または高精度表現が使用されるときに発生しますが、精度の低い値に等しいことは心配する理由ではありません。

3

いいえ、これはいつもうまくいくとは思いません。

これを実行するには、PandasがCSVファイルに書き込んだときに書き出されたテキスト値が、読み込み時に再び同じ値を復元することが必要です(Pandasを再び使用)。しかし、デフォルトでは、Pandas read_csv関数は速度の精度を犠牲にしているため、解析操作はではなく、は自動的に同じフロートを回復します。

これを実証するには、ランダムな値を作成し、それらをCSVファイルに書き出して読み込みます。すべてPandasを使用します。まず必要な輸入:

>>> import pandas as pd 
>>> import numpy as np 

は今、いくつかのランダムな値を作成し、パンダSeriesオブジェクトにそれらを置く:今、私たちは、ファイルにこれらの値を書き出すためにto_csvメソッドを使用し

>>> test_values = np.random.rand(10000) 
>>> s = pd.Series(test_values, name='test_values') 

、およびその後、バックDataFrameに、そのファイルの内容を読み取る:

>>> s.to_csv('test.csv', header=True) 
>>> df = pd.read_csv('test.csv') 

を最後に、の関連から値を抽出してみましょうdfの欄に記入し、比較する。 ==操作の結果を合計して、入力値のうちどれだけ多くが正確に回復されたかを調べます。

>>> sum(test_values == df['test_values']) 
7808 

したがって、約78%の値が正しく復元されました。他はなかった。

この動作は、バグではなく、パンダの機能と考えられます。しかし、回避策があります:Pandas 0.15が新しいfloat_precision引数をCSVリーダーに追加しました。 read_csvオペレーションにfloat_precision='round_trip'を入力することで、Pandasはより低速ですがより正確なパーサーを使用します。上記の例を試してみると、完全に回復した値が得られます。

>>> df = pd.read_csv('test.csv', float_precision='round_trip') 
>>> sum(test_values == df['test_values']) 
10000 

もう1つの例は、もう一方の方向です。前の例では、書き込みと読み取りが同じデータを戻すことはないことを示していました。この例は、読み取りと書き込みがデータを保存しないことを示しています。設定は、あなたが質問で説明するものとよく似ています。まず、定期的な間隔の値の代わりに、ランダムなものを使用して、この時間をA.csvを作成します:

>>> import pandas as pd, numpy as np 
>>> s = pd.Series(np.arange(10**4)/1e3, name='test_values') 
>>> s.to_csv('A.csv', header=True) 

は、今、私たちはA.csvを読んで、あなたのステップ1のように、B.csvに出て再びデータの前半を書きます。

>>> recovered_s = pd.read_csv('A.csv').test_values 
>>> recovered_s[:5000].to_csv('B.csv', header=True) 

はその後、我々はA.csvB.csvの両方で読み、そしてあなたのステップとして、BAの前半を比較2.

>>> a = pd.read_csv('A.csv').test_values 
>>> b = pd.read_csv('B.csv').test_values 
>>> (a[:5000] == b).all() 
False 
>>> (a[:5000] == b).sum() 
4251 

再び、いくつかの値は正しく比較されません。ファイルを開くと、A.csvは私が期待しているように見えます。ここでA.csvの最初の15エントリは次のとおりです。

,test_values 
0,0.0 
1,0.001 
2,0.002 
3,0.003 
4,0.004 
5,0.005 
6,0.006 
7,0.007 
8,0.008 
9,0.009 
10,0.01 
11,0.011 
12,0.012 
13,0.013 
14,0.014 
15,0.015 

そして、ここではB.csvで対応するエントリです:

,test_values 
0,0.0 
1,0.001 
2,0.002 
3,0.003 
4,0.004 
5,0.005 
6,0.006 
7,0.006999999999999999 
8,0.008 
9,0.009000000000000001 
10,0.01 
11,0.011000000000000001 
12,0.012 
13,0.013000000000000001 
14,0.013999999999999999 
15,0.015 

read_csvからfloat_precisionキーワードの導入の詳細については、このbug reportを参照してください。

関連する問題