首页 > 解决方案 > 为什么 Numpy 中的 0d 数组被视为标量?

问题描述

从某种意义上说,这已经有了一个很好的答案

人们不应该想太多。这最终对个人的心理健康和长寿有好处。

心理健康和长寿当然是好事,但是这个人的自尊心又如何受到打击,试图变得聪明并被 numpy 残酷地否认:

考虑以下我们从一些字节数据开始的地方:

a = np.linspace(0,255,6, dtype=np.uint8)
a
# array([  0,  51, 102, 153, 204, 255], dtype=uint8)

假设我们想要添加一些东西并提升类型,所以它不会环绕。使用标量,这不起作用:

b = np.uint16(1)

a + b
# array([  1,  52, 103, 154, 205,   0], dtype=uint8)

但是对于一个数组,它确实:

c = np.ones(1, np.uint16)

a + c
# array([  1,  52, 103, 154, 205, 256], dtype=uint16)

所以我想让我们做一个数组。

b[...]
# array(1, dtype=uint16)
np.isscalar(b[...])
# False

可惜:

a + b[...]
# array([  1,  52, 103, 154, 205,   0], dtype=uint8)

为什么这个 0d 数组在这里表现得像一个标量?

标签: pythonnumpyscalartype-promotion

解决方案


https://docs.scipy.org/doc/numpy/reference/ufuncs.html#casting-rules

最后一段:

混合标量数组操作使用一组不同的转换规则,以确保标量不能“向上转换”数组,除非标量属于与大批。此规则使您可以在代码中使用标量常量(作为 Python 类型,在 ufunc 中相应地解释),而不必担心标量常量的精度是否会导致大(小精度)数组向上转换。

我认为这意味着以下表达式具有相同的效果:

In [56]: np.add(a,1)                                                                 
Out[56]: array([  1,  52, 103, 154, 205,   0], dtype=uint8)
In [57]: np.add(a,np.array(1))                                                       
Out[57]: array([  1,  52, 103, 154, 205,   0], dtype=uint8)

为此,0d 不能“向上转换”。但是列表的行为类似于一维数组,并且会“向上转换”

In [60]: np.add(a,[1])                                                               
Out[60]: array([  1,  52, 103, 154, 205, 256])
In [61]: np.add(a,np.array([1]))                                                     
Out[61]: array([  1,  52, 103, 154, 205, 256])

https://docs.scipy.org/doc/numpy/reference/arrays.scalars.html

数组标量包括np.uint8(1)等。

数组标量对象的数组优先级为 NPY_SCALAR_PRIORITY (-1,000,000.0)。

In [67]: np.uint8(1).__array_priority__                                              
Out[67]: -1000000.0
In [68]: np.array(1,'uint8').__array_priority__                                      
Out[68]: 0.0

数组标量具有与数组完全相同的方法。这些方法的默认行为是在内部将标量转换为等效的 0 维数组并调用相应的数组方法。

np.isscalar做:

        (isinstance(num, generic)
        or type(num) in ScalarType
        or isinstance(num, numbers.Number))

np.isscalar建议使用np.ndim(x) == 0. 这首先检查一个.ndim属性(这将是 0d 数组的情况),如果失败,则尝试np.asarray(x).ndim. 所以从这个意义上说,任何可以做成 0d 数组的东西都可以称为“标量”。这可能太宽泛了,因为字典很重要:npdim({}).


推荐阅读