2017-05-29 13 views
1

pandas.read_csvを使用してCSVから確率を読み取る際に問題があります。値の一部は> 1.0で浮動小数点として読み込まれます。pandas.read_csv()float解析の理解

具体的には、私は次の動作について混乱しています:

>>> pandas.read_csv(io.StringIO("column\n0.99999999999999998"))["column"][0] 
1.0 
>>> pandas.read_csv(io.StringIO("column\n0.99999999999999999"))["column"][0] 
1.0000000000000002 
>>> pandas.read_csv(io.StringIO("column\n1.00000000000000000"))["column"][0] 
1.0 
>>> pandas.read_csv(io.StringIO("column\n1.00000000000000001"))["column"][0] 
1.0 
>>> pandas.read_csv(io.StringIO("column\n1.00000000000000008"))["column"][0] 
1.0 
>>> pandas.read_csv(io.StringIO("column\n1.00000000000000009"))["column"][0] 
1.0000000000000002 

デフォルトフロート-解析する行動は、非単調であると思われる、と0.9...を開始特に、いくつかの値が1.0より厳密に大きいフロートに変換され、例えば問題を引き起こすsklearn.metricsにそれらを供給するとき。

documentationread_csvは、「Cエンジンは、浮動小数点値のために使用すべきコンバータ」を選択するために使用できるパラメータfloat_precisionを持っていることを述べ、及び'high'にこれを設定すると、確かに私の問題を解決します。

しかし、私は、デフォルトの動作を理解したいと思います:

    私はデフォルトのフロートコンバータのソースコードを見つけることができます
  1. デフォルトのフロートコンバータと他の選択肢の意図された動作に関するドキュメントはどこにありますか?
  2. 最下位位置の単数形の変更が値をスキップするのはなぜですか?
  3. なぜこれは単調に動作しませんか?

「重複する質問」に関する編集:これは重複していません。私は浮動小数点数学の限界を認識しています。

>>> float("0.99999999999999999") 
1.0 

...と私はドキュメントを見つけることができませんでした:組み込みfloatは、この動作を示していないので、私は具体的には、パンダのデフォルトの解析メカニズムについて尋ねました。

+0

[浮動小数点数学は壊れていますか?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – pvg

+4

@pvg、これは欺瞞ではありません。 OPは非単調な挙動を注意深く実証しており、生産的に作業できるようにいくつかの照明を求めています。 –

+0

@StephenRauchそれは偽薬か関連する偽薬です。希望の精度と結果を見てみると、これらはすべてieee doubleのイプシロンよりも小さい。それは実際に操作するのに賢明な場所ではありません。 – pvg

答えて

1

@MaxUはすでにパーサーのソースコードと関連するトークナイザを示しました。 xstrtodだから私は "なぜ"の部分に焦点を当てます:

xstrtodのためのコードは、おおよそこの(ピュアPythonに翻訳された)のようなものです:

「問題は」あなたが見た再現
def xstrtod(p): 
    number = 0. 
    idx = 0 
    ndecimals = 0 

    while p[idx].isdigit(): 
     number = number * 10. + int(p[idx]) 
     idx += 1 

    idx += 1 

    while idx < len(p) and p[idx].isdigit(): 
     number = number * 10. + int(p[idx]) 
     idx += 1 
     ndecimals += 1 

    return number/10**ndecimals 

print(xstrtod('0.99999999999999997')) # 1.0 
print(xstrtod('0.99999999999999998')) # 1.0 
print(xstrtod('0.99999999999999999')) # 1.0000000000000002 
print(xstrtod('1.00000000000000000')) # 1.0 
print(xstrtod('1.00000000000000001')) # 1.0 
print(xstrtod('1.00000000000000002')) # 1.0 
print(xstrtod('1.00000000000000003')) # 1.0 
print(xstrtod('1.00000000000000004')) # 1.0 
print(xstrtod('1.00000000000000005')) # 1.0 
print(xstrtod('1.00000000000000006')) # 1.0 
print(xstrtod('1.00000000000000007')) # 1.0 
print(xstrtod('1.00000000000000008')) # 1.0 
print(xstrtod('1.00000000000000009')) # 1.0000000000000002 
print(xstrtod('1.00000000000000019')) # 1.0000000000000002 

問題は最後の場所で9のようですその結果が変わる。だから、ポイント精度浮動います:

>>> float('100000000000000008') 
1e+17 
>>> float('100000000000000009') 
1.0000000000000002e+17 

それは偏った結果に責任がある最後の場所で9です。

>>> import pandas 
>>> import decimal 
>>> converter = {0: decimal.Decimal} # parse column 0 as decimals 
>>> import io 
>>> def parse(string): 
...  return '{:.30f}'.format(pd.read_csv(io.StringIO(string), converters=converter)["column"][0]) 
>>> print(parse("column\n0.99999999999999998")) 
>>> print(parse("column\n0.99999999999999999")) 
>>> print(parse("column\n1.00000000000000000")) 
>>> print(parse("column\n1.00000000000000001")) 
>>> print(parse("column\n1.00000000000000008")) 
>>> print(parse("column\n1.00000000000000009")) 

出力します:あなたはarbitary精度をしたい場合は、すなわちdecimal.Decimal独自のコンバータまたは使用のpython-提供するものを、定義することができ、高精度が必要な場合


0.999999999999999980000000000000 
0.999999999999999990000000000000 
1.000000000000000000000000000000 
1.000000000000000010000000000000 
1.000000000000000080000000000000 
1.000000000000000090000000000000 

入力を正確に表す!

+0

私は 'xstrtod'ソース(感謝@MaxU)を見ました。問題は中間結果、特に 'number'に不正確な可能性があり、いくつかの文字列が最も近い表現可能なfloat *にならないような方法で解析される可能性があることです。 (また、指数のオーバーフローがチェックされていません。) – user4235730

+0

私の意見では、 "高い"精度がデフォルトで使用されるべきです。この現象は、私が予想しているよりも高く、検出するのが困難な数値エラーにつながります。 *ほとんどの場合、この動作を文書化する必要があります。*(または関連する文書が見つかった人はいますか?) – user4235730

+0

いいえ、私はその動作のドキュメントを発見していません。 Fortunatlyほとんどの場合、数字は10小数点以下を持っていないし、これらの数字は "十分に"動作します。それがあなたのための最適化です: – MSeifert

1

あなたはそれがどのように動作するかを理解したい場合は - source code - file "_libs/parsers.pyx" lines: 492-499 for Pandas 0.20.1を見て:

self.parser.double_converter_nogil = xstrtod # <------- default converter 
    self.parser.double_converter_withgil = NULL 
    if float_precision == 'high': 
     self.parser.double_converter_nogil = precise_xstrtod # <------- 'high' converter 
     self.parser.double_converter_withgil = NULL 
    elif float_precision == 'round_trip': # avoid gh-15140 
     self.parser.double_converter_nogil = NULL 
     self.parser.double_converter_withgil = round_trip 

Source code for xstrtod

Source code for precise_xstrtod

関連する問題