使用 numpy 创建十进制数范围不起作用

Create a range of decimal number using numpy does not work

我想创建一个介于 521 和 522 之间的值范围,步长为 0.1。这是我的代码:

ICD9CD1 = np.arange(521, 522, 0.1)

结果是:

array([521. , 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8,
       521.9])

但是当我想把它转换成一个列表时,结果是这样的:

np.arange(521, 522, 0.1).tolist()

[521.0,
 521.1,
 521.2,
 521.3000000000001,
 521.4000000000001,
 521.5000000000001,
 521.6000000000001,
 521.7000000000002,
 521.8000000000002,
 521.9000000000002]

我的代码哪一部分有问题?我想要这个列表作为我的输出: [521。 , 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8, 521.9]

试试这个:

import numpy as np
list(np.around(np.arange(521, 522, 0.1),2))

arange 文档警告:

When using a non-integer step, such as 0.1, the results will often not be consistent. It is better to use numpy.linspace for these cases.

您看到的是浮点不精确和生成连续值的 arange 方式的组合。浮点值永远不会精确。

arange 建议使用带小数步长的 linspace。请注意选择正确的数字:

In [301]: np.linspace(521,522,11)                                                                                    
Out[301]: 
array([521. , 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8,
       521.9, 522. ])
In [302]: np.linspace(521,522,11).tolist()                                                                           
Out[302]: [521.0, 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8, 521.9, 522.0]

生成整数值并缩放它们也有效:

In [303]: (np.arange(5210,5220)/10)                                                                                  
Out[303]: 
array([521. , 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8,
       521.9])
In [304]: (np.arange(5210,5220)/10).tolist()                                                                         
Out[304]: [521.0, 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8, 521.9]

这也可以通过 python 的 range:

来完成
In [305]: [i/10 for i in range(5210,5220)]                                                                           
Out[305]: [521.0, 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8, 521.9]

您应该使用 np.arange(5210, 5220) / 10np.linspace(521, 522, 10, endpoint=False),但请阅读整个答案。


你的部分代码错误的,但不是你想的那样。

浮点运算有舍入误差。这是浮点数的基础,也是尝试在资源有限的计算机上执行实数计算的基本限制。即使是符号计算也无法解决问题 - 当无法对表达式进行符号化简化时,您最终只会构建巨大的表达式树,而不是实际计算任何东西。

仅在您的输出中存在舍入误差并不意味着您做错了什么。此外,舍入错误已经出现在 arange 输出中,只是被 NumPy 的默认打印设置隐藏了——它没有在 tolist 调用中引入。对于任何稍微重要的浮点计算,您永远无法消除所有舍入误差。

即使结果看起来像 [521. , 521.1, 521.2, 521.3, 521.4, 521.5, 521.6, 521.7, 521.8, 521.9] 实际上也会有舍入误差,因为实数 521.1 实际上不能用二进制浮点数表示。大多数看起来像在该列表中的数字都不能用二进制浮点数表示。 (64 位)浮点数 521.1 实际上是 521.1000000000000227373675443232059478759765625,但大多数编程语言默认情况下不会显示确切的值。


您的代码中真正错误的部分是使用 arange 和浮点输入。 arange 与浮点输入不一致,因为根据舍入误差,它可能包含比预期更多或更少的元素。例如,

np.arange(1, 1.3, 0.1)

returns

array([1. , 1.1, 1.2, 1.3])

而不是

array([1. , 1.1, 1.2])

由于在计算结果长度时出现浮点舍入错误。

此外,由于一些奇怪的实施决策,arange 浮点输入的舍入误差比应有的多得多,即使它获得正确的输出大小时也是如此。

np.linspace 旨在避免 arange 的问题。它直接将输出大小作为参数,而不是从步骤中计算出来,并且有一个明确的参数来决定是否包含正确的端点。这避免了输出大小计算中的舍入错误,只要您不通过计算浮点输出大小来自己引入它。在计算输出元素时,np.linspace 的舍入误差也小于 arange。它不能保证尽可能少的舍入误差——例如,np.linspace(0, 3, 148)[::49].tolist() 显示多余的舍入误差——但它比浮点数 arange.

好很多

np.arange(5210, 5220) / 10 使用带有整数参数的 arange 然后除法。此选项只有一个舍入误差来源,即除以 10。IEEE 754 规范保证此除法 正确舍入 ,因为结果将舍入为浮点数最接近除法的理想实数结果的点值。此选项保证最小舍入误差,在某些情况下优于 linspace。例如,np.arange(148) / 49 在舍入误差方面优于 np.linspace(0, 3, 148)