Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何修复产生不精确结果的numpy浮点运算?_Python_Pandas_Numpy_Comparison_Floating Accuracy - Fatal编程技术网

Python 如何修复产生不精确结果的numpy浮点运算?

Python 如何修复产生不精确结果的numpy浮点运算?,python,pandas,numpy,comparison,floating-accuracy,Python,Pandas,Numpy,Comparison,Floating Accuracy,我需要从已知样本大小的相对频率重建绝对频率 这应该很简单,但是绝对频率和样本量是numpy.int64,相对频率是numpy.float64 我知道浮点十进制值通常没有精确的二进制表示,我们可能会经历一些精度损失。似乎是这样,浮点运算产生了意想不到的结果,我不能相信重建的绝对频率 复制错误的示例代码: import pandas as pd import numpy as np absolutes = np.arange(100000, dtype=np.int64) #numpy.int64

我需要从已知样本大小的相对频率重建绝对频率

这应该很简单,但是绝对频率和样本量是
numpy.int64
,相对频率是
numpy.float64

我知道浮点十进制值通常没有精确的二进制表示,我们可能会经历一些精度损失。似乎是这样,浮点运算产生了意想不到的结果,我不能相信重建的绝对频率

复制错误的示例代码:

import pandas as pd
import numpy as np

absolutes = np.arange(100000, dtype=np.int64) #numpy.int64
sample_size = absolutes.sum() # numpy.int64
relatives = absolutes / sample_size #float64

# Rebuilding absolutes from relatives

rebuilt_float = relatives * sample_size #float64
rebuilt_int = rebuilt_float.astype(np.int64)

df = pd.DataFrame({'absolutes': absolutes,
                   'relatives': relatives,
                   'rebuilt_float': rebuilt_float,
                   'rebuilt_int': rebuilt_int})

df['check_float'] = df['absolutes'] == df['rebuilt_float']
df['check_int'] = df['absolutes'] == df['rebuilt_int']

print('Failed FLOATS: ', len(df[df['check_float'] == False]))
print('Failed INTS:', len(df[df['check_int'] == False]))
print('Sum of FLOATS:', df['rebuilt_float'].sum())
print('Sum of INTS:', df['rebuilt_int'].sum())

使用numpy解决这个问题而不将每个数字都转换为十进制是可能的吗

如果在转换为整数之前对重建的值进行四舍五入,则会得到零个失败整数。即使用

rebuilt_int = np.round(rebuilt_float).astype(np.int64)
然后输出为

Failed FLOATS:  11062
Failed INTS: 0
Sum of FLOATS: 4999950000.0
Sum of INTS: 4999950000
np.isclose(df['absolutes',df['rebuilded\u float',atol=.99999)

是一个不精确的fp感知比较。它有一个额外的args
atol
rtol
用于相对和绝对公差

您可以通过更改
atol
来查看消除了多少舍入错误:

>>> len(np.where( np.isclose(df['absolutes'], df['rebuilt_int'], atol=.99999) == False )[0])
0
>>> len(np.where( np.isclose(df['absolutes'], df['rebuilt_int'], atol=.5) == False )[0])
2767
>>> len(np.where( np.isclose(df['absolutes'], df['rebuilt_int'], atol=1) == False )[0])
0

你的问题是乘法不精确,还是比较不精确?基本上,您希望在哪里进行舍入(或强制)?是一种可感知fp的不精确比较,它可以做您想要的事情,并且是矢量化的。问题是乘法是不精确的。按照Warren的建议,在转换为int64之前进行舍入。使用numpy.isclose()进行比较很好。您当前的舍入比
numpy.isclose(,atol)
差。由于
astype(np.int64)
四舍五入,例如df['rebuilded_float'][5]变成了4.9999999999999,而
astype(np.int64)
似乎转换成了4,所以有一半的浮点出现了严重错误。你看到了吗?是的,我在Jupyter中看到了:df['rebuilded_float'][5]是4.9999999991,df['rebuilded_float'][5])。astype(np.int64)将其转换为4,这不是我所期望的。但是如果在转换之前进行四舍五入,则np.round(df['rebuilded_float'][5])。astype(np.int64)给出5,这是我想要的结果。