首页 > 解决方案 > Python - numpy 数组、小数位、浮点数和小数点的平均值

问题描述

考虑以下代码(Windows 10 上 MSYS2 中 MINGW64 上的 Python 3.8.0):

import numpy as np
from decimal import Decimal

aa = [25744, 25687, 25641, 25601, 25566, 25533, 25505, 25479, 25456, 25435]
npaa = np.array(aa)

print(np.mean(npaa))                            # 25564.7
print(0.001*np.mean(npaa))                      # 25.564700000000002

print( Decimal(np.mean(npaa)) )                 # 25564.70000000000072759576141834259033203125
print( Decimal(0.001)*Decimal(np.mean(npaa)) )  # 25.56470000000000125976798437

因此,上述整数列表的平均值最初打印为 25564.7,这是我期望和想要得到的。

但是,一旦我将这个数字乘以 0.0001,我就会得到大量小数,这可能是因为浮点(im)精度。

所以,我想 - 到底是什么,我只是要使用 Decimal 类,然后在这种情况下我应该得到“正确”的小数位数。

但是,一旦我尝试Decimal(np.mean(npaa)),我就得到了一堆小数的平均值:25564.70000000000072759576141834259033203125

显然,np.mean(npaa)已经包含了这些小数 - 但出于某种原因,它们只是没有被打印出来。

所以这就是问题 - 因为我在列表中的所有内容都是整数,并且列表中有 10 个,从数学上(在这种情况下)我不可能得到任何其他结果,除了一个带有 1 个小数和 1 个小数的数字只要。

现在,我可以通过将平均数打印为字符串来解决这个问题,并将其格式化为 1 个小数,如 中"{:.1f}".format(np.mean(npaa)),然后使用该字符串作为小数的源 - 这很有效;但是,我有其他长度不是 10 的数组,我希望变量中自动出现最小的小数位数 - 无需我手动确定我应该期望的小数位数,然后格式化它们作为字符串。

所以我可以尝试使用一个小数数组,(正如链接的帖子试图做的那样),这并不是微不足道的:

print( np.array(aa, dtype=Decimal) )          # [25744 25687 25641 25601 25566 25533 25505 25479 25456 25435]
print( np.array(aa).astype(Decimal) )         # [25744 25687 25641 25601 25566 25533 25505 25479 25456 25435]
print( np.array([Decimal(ax) for ax in aa]) ) # [Decimal('25744') Decimal('25687') Decimal('25641') Decimal('25601') Decimal('25566') Decimal('25533') Decimal('25505') Decimal('25479')  Decimal('25456') Decimal('25435')]

print( np.mean( np.array([Decimal(ax) for ax in aa]) ) )                # 25564.7
print( type(np.mean( np.array([Decimal(ax) for ax in aa]) )) )          # <class 'decimal.Decimal'>
print( Decimal(0.001)*np.mean( np.array([Decimal(ax) for ax in aa]) ) ) # 25.56470000000000053217222296

...然而,即使我现在有一个Decimal25564.7 和一个Decimal0.001,当我将它们相乘时 - 在Decimal域中!- 我仍然得到 25.56470000000000053217222296 !?

我怎么能让 Python 将 0.001*25564.7 计算为 25.5647,它应该是这样的 - 无需“强制转换”,也就是说,将十进制/浮点值打印为小数位数有限的字符串?Decimal 类不应该能够做到这一点吗?


编辑:所以,我也尝试sum()/len()了方法,就像在链接的帖子中一样 - 我起初认为它可以做到,但没有:

print( sum(aa)/len(aa) )                # 25564.7
print( 0.001*sum(aa)/len(aa) )          # 25.5647
print( Decimal(0.001*sum(aa)/len(aa)) ) # 25.564699999999998425437297555617988109588623046875

print( sum(npaa)/len(npaa) )                 # 25564.7
print( 0.001*sum(npaa)/len(npaa) )           # 25.5647
print( Decimal(0.001*sum(npaa)/len(npaa)) )  # 25.564699999999998425437297555617988109588623046875

https://docs.python.org/2/tutorial/floatingpoint.html

顺便说一下,decimal 模块还提供了一种很好的方法来“查看”存储在任何特定 Python 浮点数中的确切值

https://docs.python.org/2/library/decimal.html

十进制数可以精确表示。相反,数字喜欢1.1并且2.2不具有二进制浮点的精确表示。最终用户通常不会期望像使用二进制浮点那样1.1 + 2.2显示。3.3000000000000003

那么,如果Decimal数字可以精确表示,为什么Decimal在这种情况下使用该类时会得到相同的浮点不精度?

标签: pythonpython-3.xnumpydecimal

解决方案


好的,我将把它作为答案发布 - 感谢@user2357112 的评论,现在我知道,无论最初如何打印浮点数(可能是四舍五入),如果我将浮点数投掷/投射到a Decimal,我仍然会得到相同的舍入误差。所以,我要么必须从一开始就处理整数级别,要么处理字符串级别。

因此,在这种特殊情况下(数组中的整数,寻找平均值),我可以这样做:

tmean = Decimal(int(sum(npaa)))/Decimal(len(npaa))
print( type(tmean), tmean ) # <class 'decimal.Decimal'> 25564.7

所以,我基本上首先运行数组的总和,结果是一个整数,我将其转换为Decimal. 请注意,我首先必须将 sum 转换为 Python builtin int,否则:

Decimal(sum(npaa))/Decimal(len(npaa)) # TypeError: conversion from numpy.int32 to Decimal is not supported

事实证明,将整个 numpy 数组“转换”为 Python 内置函数是非常困难的int创建和使用 dtype 为内置 int 的 NumPy 数组- 所以剩下的唯一一件事就是将总和转换为单个数字,到内置int.

但是一旦完成,我将平均计算作为两个Decimal类整数的除法 - 在这种情况下,我可以合理地期望在平均数的最终计算中正确的小数位数(在这种情况下,一个)。

编辑:最后,如果我想计算这个平均乘以 0.001,我需要将它用作字符串Decimal('0.001')*tmean来获得正确的小数位数 - 如果我只使用Decimal(0.001)浮点参数,浮点不精确会已经蔓延中,并且仅使用Decimal该类已无济于事。


推荐阅读