脾气暴躁:就地和显式操作的奇怪不同行为

时间:2018-08-20 12:06:13

标签: 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

为什么x的类型不同于y?我知道,就地操作的实现方式不同,它们不创建数组的副本,但是我不明白,如果我将0d数组与浮点数相乘,为什么要更改类型?它适用于一维数组:

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

我认为,这很奇怪...现在我遇到了以下问题,我将不得不分别处理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

1 个答案:

答案 0 :(得分:0)

最终,这种行为归结于开发人员的自由选择,因此不必存在良好的解释。但是,我想捍卫/解释所观察到的行为,如下所述。

对于

y = np.array(1.)
y *= 1.

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

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

x = 1.*np.array(1.)情况下,我们将其白化为

x1 = 1.
x2 = np.array(1.)
x = x1*x2

在这里,我们不创建对象,然后对它进行操作。相反,我们创建两个对象x1x2,然后使用对称操作(此处为二进制乘法)将它们组合为第三个对象x。由于x1x2碰巧具有不同(但兼容)的类型,因此x的类型并不明显:它也很可能是x1({ {1}}或floatx2)的类型。令人惊讶的是,实际答案都不是,因为numpy.ndarray的类型是x。这种行为源于两个单独的选择。

选择1

将0维数组与标量组合会产生标量,而不是0维数组。的确,这是使您绊倒的选择。我想它也可能是反过来选择的。全局切换(例如np.float64)将是一个不错的功能!

选择2

将NumPy数字数据类型与标准Python数字类型组合会产生NumPy数字数据类型。在这里,第一类包括诸如np.return_scalar = Falsenp.int64,{{1 }}(还有更多),而后者仅由np.float64np.complex128int组成(对于Python 2,也是float)。因此,complexlong的结果是float

这两个选择确实使np.float64成为dtype np.float64的NumPy标量。