当我为给定的 dtype 设置太大的值时会发生啥?

Posted

技术标签:

【中文标题】当我为给定的 dtype 设置太大的值时会发生啥?【英文标题】:What happens when I set values that are too big for a given dtype?当我为给定的 dtype 设置太大的值时会发生什么? 【发布时间】:2014-04-27 11:35:05 【问题描述】:

所以我总是这样创建 numpy 数组:

>>> u = np.zeros( 10, int )
>>> v = np.zeros( 10, float )

到目前为止,我一直对最大允许值一无所知。我一直假设它会简单地工作。如果没有,我会得到OverflowError,然后我会找到一些解决方法,比如取对数。

但最近我开始使用其他 dtypes:

>>> v8 = np.zeros( 10, np.uint8 )
>>> v8[0] = 2 ** 8 - 1
>>> v8[1] = 2 ** 8
>>> v8
>>> array([255,   0,   0,   0,   0,   0,   0,   0,   0,   0], dtype=uint8)

好的,所以当我分配一个大于 255 的值时,我不会收到任何警告。这有点吓人。

所以我的问题是:

当我使用intfloat 类型的数组时,是否有可能我在不知情的情况下设置了一个太大的值(导致完全错误的计算)? 如果我想使用uint8,是否必须手动检查所有分配的值是否在[ 0, 255 ] 中?

【问题讨论】:

【参考方案1】:

numpy 在机器级别的工作非常深入。测试非常耗时,因此测试留给了开发人员。 Python 更高级,许多测试是自动完成的,或者在整数的情况下,整数可以有任意大的值。在任何地方,您都必须在速度和安全性之间做出选择。 numpy 在速度方面更远。

在需要测试值范围的情况下,您必须自己检查。

剪辑-方法可以帮助你:

>>> u = np.array([124,-130, 213])
>>> u.astype('b')
array([124, 126, -43], dtype=int8)
>>> u.clip(-128,127).astype('b')
array([ 124, -128,  127], dtype=int8)

【讨论】:

【参考方案2】:

正如其他答案中所解释的,太大的值会被“环绕”,因此您需要在转换之前将它们手动剪辑到允许的最小值和最大值。对于整数,可以使用np.iinfo 获得这些限制。您可以编写自己的实用程序函数,以安全的方式为给定的 dtype 执行此转换:

def safe_convert(x, new_dtype):
    info = np.iinfo(new_dtype)
    return x.clip(info.min, info.max).astype(new_dtype)

快速测试:

In [31]: safe_convert(np.array([-1,0,1,254,255,256]), np.uint8)
Out[31]: array([  0,   0,   1, 254, 255, 255], dtype=uint8)

In [32]: safe_convert(np.array([-129,-128,-127,126,127,128]), np.int8)
Out[32]: array([-128, -128, -127,  126,  127,  127], dtype=int8)

【讨论】:

【参考方案3】:

是的,uint8 会屏蔽你的值(取 8 lsb),所以你需要手动检查它:

>>> a = numpy.uint8(256)
>>> a
0

是的,溢出可能会在您没有意识到的情况下发生。它是许多编程语言中常见的错误来源。然而,python 中的长整数以一种不常见的方式表现:它们没有明确定义的限制。

我已经在this answer 中写过它。

【讨论】:

【参考方案4】:

如前所述,numpy 环绕以避免进行检查。

如果剪辑不可接受,则在投射之前,您可以使用numpy.min_scalar_type 来获取能够在不丢失数据的情况下保存数据的最小 dtype。

还要注意,实际上使用uint8 的唯一原因是在非常大的数组中节省内存,因为计算速度通常大致相同(在某些操作中甚至会在内部向上转换)。如果您的数组不是太大以至于内存不是一个大问题,您应该更安全并使用uint16 甚至uint32 进行中间计算。如果内存是你的问题,你应该考虑转移到核心存储之外,比如 PyTables;如果您现在要填满内存,可能使用更大的数据集甚至 uint8 都不够。

【讨论】:

以上是关于当我为给定的 dtype 设置太大的值时会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

“输入包含 NaN、无穷大或对于 dtype('float32') 来说太大的值”当我训练 DecisionTreeClassifier [关闭]

SVM ValueError:输入包含 NaN、无穷大或对于 dtype('float64') 来说太大的值

输入包含无穷大或对于 dtype('float64') 错误来说太大的值

Python - 输入包含 NaN、无穷大或对于 dtype('float64') 来说太大的值

GridSearchCV():ValueError:输入包含 NaN、无穷大或对于 dtype('float64') 来说太大的值

Jupiter Notebook:输入包含 NaN、无穷大或对于 dtype('float64') 来说太大的值