python - 了解 pandas.read_csv() 浮点解析

标签 python pandas floating-accuracy

我在使用 pandas.read_csv 从 CSV 读取概率时遇到问题;一些值被读取为带有 > 1.0 的 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 的 float ,导致问题,例如当将它们输入 sklearn.metrics 时。

documentation指出 read_csv 有一个参数 float_precision 可用于选择“C 引擎应该使用哪个转换器来处理浮点值”,并将其设置为 ' high' 确实解决了我的问题。

但是,我想了解默认行为:

  1. 在哪里可以找到默认浮点转换器的源代码?
  2. 我在哪里可以找到有关默认浮点转换器的预期行为和其他可能选择的文档?
  3. 为什么最不重要位置的单个数字变化会跳过一个值?
  4. 为什么这根本不是单调的?

关于“重复问题”的编辑:这不是重复问题。我知道 float 学的局限性。我特别询问 Pandas 中的默认解析机制,因为内置的 float 不显示此行为:

>>> float("0.99999999999999999")
1.0

...我找不到文档。

最佳答案

@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


如果您想要高精度,您可以定义自己的转换器或使用 python 提供的转换器,即 decimal.Decimal 如果您想要任意精度:

>>> 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"))

打印:

0.999999999999999980000000000000
0.999999999999999990000000000000
1.000000000000000000000000000000
1.000000000000000010000000000000
1.000000000000000080000000000000
1.000000000000000090000000000000

准确代表输入!

关于python - 了解 pandas.read_csv() 浮点解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44247486/

相关文章:

python - 使用 Pandas 计算 TimeField 小时/分钟总和

Python Pandas 按多个类别和年份交叉表

python - 使用 loc 的 Pandas 浮点值问题

math - float 学有问题吗?

python - 通过分隔符拆分 Pandas 数据框列

performance - 在 Haskell 中运行跨平台、确定性模拟的最有效方法是什么?

python - 我应该使用 __new__ 来防止实例化吗?

python - 在Python中延迟解析有状态的、每记录多行的数据流?

python - Google Ads API 指标成本、每次点击费用等太大了

python - 从另一个数据框中删除具有相同值的行