Numpy:inplace和explicit操作的奇怪的不同行为

gre*_*een 7 python arrays numpy in-place numpy-ndarray

我想操作numpy数组来使用它们的索引,我想要包含0维的情况.现在我遇到了一个奇怪的情况,如果我不使用就地乘法,则会出现类型转换:

In [1]: import numpy as np

In [2]: x = 1.*np.array(1.)

In [3]: y = np.array(1.)

In [4]: y *= 1.

In [5]: x
Out[5]: 1.0

In [6]: y
Out[6]: array(1.)

In [7]: type(x)
Out[7]: numpy.float64

In [8]: type(y)
Out[8]: numpy.ndarray
Run Code Online (Sandbox Code Playgroud)

为什么x的类型与y不同?我知道,inplace操作是不同的实现,他们不创建数组的副本,但我不明白,为什么类型被更改,如果我将一个0d数组与浮点数相乘?它适用于1d阵列:

In [1]: import numpy as np

In [2]: x = np.array(1.)

In [3]: y = np.array([1.])

In [4]: 1.*x
Out[4]: 1.0

In [5]: 1.*y
Out[5]: array([1.])

In [7]: type(1.*x)
Out[7]: numpy.float64

In [8]: type(1.*y)
Out[8]: numpy.ndarray
Run Code Online (Sandbox Code Playgroud)

我想,这很奇怪......现在我遇到了以下问题,我必须分别处理0d数组:

In [1]: import numpy as np

In [2]: x = np.array(1.)

In [3]: y = np.array(1.)*1.

In [4]: x[x>0]
Out[4]: array([1.])

In [5]: y[y>0]
Out[5]: array([1.])

In [6]: x[x>0] = 2.

In [7]: y[y>0] = 2.
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-5f9c5b138fc0> in <module>()
----> 1 y[y>0] = 2.

TypeError: 'numpy.float64' object does not support item assignment
Run Code Online (Sandbox Code Playgroud)

jmd*_*_dk 1

最终,这种行为归结为开发人员做出的自由选择,因此不一定存在好的解释。然而,我想对观察到的行为进行如下辩护/解释。

如果是

y = np.array(1.)
y *= 1.
Run Code Online (Sandbox Code Playgroud)

我们创建一个np.ndarray对象y,然后对其进行操作。在这里,最自然的行为是操作(可能)改变的y,而类型应保持不变。这确实是实际发生的情况。

另外,请注意type和 NumPy 数据类型(或dtype)之间的区别。y = np.array(1)如果我们从(dtype of )开始np.int64,该操作y *= 1.现在是非法的,因为这需要dtype就地更改!

对于这种情况x = 1.*np.array(1.),让我们将其白化为

x1 = 1.
x2 = np.array(1.)
x = x1*x2
Run Code Online (Sandbox Code Playgroud)

在这里,我们不创建一个对象然后对其进行操作。相反,我们创建两个对象x1x2,然后x使用对称运算(此处为二进制乘法)将它们组合成第三个对象 。由于x1x2恰好具有不同(但兼容)的类型,因此 的类型x是非显而易见的:它同样可以是x1( ) 的类型或( )float的类型。令人惊讶的是,实际答案都不是,因为 的类型是。这种行为源于两个不同的选择。x2numpy.ndarrayxnp.float64

选择1

将 0 维数组与标量组合会产生标量,而不是 0 维数组。这确实是一个让你绊倒的选择。我想也可能是反过来选择的。全局开关(例如np.return_scalar = False)将是一个很好的功能!

选择2

将 NumPy 数值数据类型与标准 Python 数值类型相结合会产生 NumPy 数值数据类型。在这里,第一类包括np.int64, np.float64, np.complex128(以及更多),而后者仅包含int,floatcomplex(对于 Python 2,还有long)。因此,float时间np.float64导致np.float64

综合起来,这两个选择确实产生了x = 1.*np.array(1.)dtype 的 NumPy 标量np.float64