【问题标题】:Is there a better way to assign a new value to a numpy array scalar?有没有更好的方法来为 numpy 数组标量分配新值?
【发布时间】:2018-09-09 21:29:54
【问题描述】:

我正在对 numpy 数组中的标量值进行一些快速计算。正如documentation 中所说,

使用数组标量的主要优点是它们保留了 数组类型(Python 可能没有可用的匹配标量类型,例如 int16)...

但是有没有比这更好(更快,更简洁)的方法来为现有数组标量分配新值:

>>> x = np.array(2.0, dtype='float32')

这可行,但不是那么方便(我正在做其他算术并希望始终保留类型)。

由于显而易见的原因,这不起作用:

>>> x = np.array(1.0, dtype='float32')
>>> print(x, type(x))
1.0 <class 'numpy.ndarray'>
>>> x = 2.0
>>> print(x, type(x))
2.0 <class 'float'>

这也不行:

>>> x = np.array(1.0, dtype='float32')
>>> x[] = 2.0
  File "<ipython-input-319-7f36071ff81d>", line 2
    x[] = 2.0
      ^
SyntaxError: invalid syntax

也不是这样:

>>> x = np.array(1.0, dtype='float32')
>>> x[:] = 2.0
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-24-62cd4ca238ce> in <module>()
      1 x = np.array(1.0, dtype='float32')
----> 2 x[:] = 2.0

IndexError: too many indices for array

更新:

基于下面的 cmets(谢谢),我现在意识到我实际上并没有使用数组标量。 x 是一个零维数组。

这里是如何创建一个数组标量:

>>> a = np.array((1.0, 2.0, 3.0), dtype='float32')
>>> x = a[0]
>>> print(x, type(x))
1.0 <class 'numpy.float32'>

或者简单地说:

>>> x = np.float32(1.0)
>>> print(x, type(x))
1.0 <class 'numpy.float32'>

【问题讨论】:

  • 另外,即使它们是可变的——x = 2.0 只是重新绑定名称 x 以指向不同的对象。它唯一改变的是全局命名空间。 (如果您是从另一种语言(尤其是 C++)转向 Python,这可能是您的困惑。x 不是 C++ 意义上的变量,即具有类型和值的内存位置,它只是命名空间绑定中的名称到一个对象,并且该对象具有内存位置、类型和值。)
  • @abarnert NumPy 标量(例如x)只是形状为() 的数组。正如 hpaulj 的回答所示,它们可变的。
  • 谢谢@abarnet。我将更正问题中的代码以将x = np.array((2.0), dtype='float32') 更改为x = np.array(2.0, dtype='float32')。我认为这个问题仍然有效。
  • @jmd_dk: x 不是数组标量。 numpy.float32(1.0) 将是一个数组标量。 x 是一个 0 维数组。
  • @Bill 如果您重新表述问题,请显示 both np.float32(1.0)np.array(1.0, dtype=np.float32),并展示您如何尝试所有不同的方法(也可以尝试 x[:] = 2.0,这会给你一个信息性错误),然后答案会比现在更适合你的问题。

标签: python arrays numpy scalar copy-assignment


【解决方案1】:

可以修改 0d 数组,但 array scalar 不能:

In [199]: x = np.array(1.0, 'float32')
In [200]: x
Out[200]: array(1., dtype=float32)
In [201]: x.shape
Out[201]: ()
In [202]: x[...] = 2
In [203]: x
Out[203]: array(2., dtype=float32)
In [204]: x[()] =3
In [205]: x
Out[205]: array(3., dtype=float32)

您必须改变x,而不是为变量分配新对象。

也就是说,我不明白为什么人们想要或需要这样做。


这个0d数组和array scalar不太一样:

In [207]: y = np.float32(1)
In [208]: y[...] = 2
....
TypeError: 'numpy.float32' object does not support item assignment

从带有索引的数组中提取元素会生成array scalar

In [210]: type(x[()])
Out[210]: numpy.float32

float32 对象有很多数组属性,甚至是方法,但并不完全相同:

In [211]: x.shape
Out[211]: ()
In [212]: y.shape
Out[212]: ()

可以使用与其形状大小相同的元组来索引数组。 arr[1,2]arr[(1,2)] 相同。 x的形状是(),所以只能用空元组x[()]来索引。同样arr[:,:] 适用于二维数组,但不适用于一维数组。 ... 表示任意数量的切片,因此可以与 x[...] 一起使用。

已经为np.generic 类对象定义了足够的__getitem__,以允许像[...][()] 这样的索引。但尚未定义分配。

查看 np.ndarraynp.int_np.float32np.floatnp.int 等类的类层次结构可能很有用。

更完整的报价

来自您的链接:https://docs.scipy.org/doc/numpy-1.13.0/user/basics.types.html#array-scalars

NumPy 通常将数组元素作为数组标量(具有关联 dtype 的标量)返回。数组标量与 Python 标量不同,但在大多数情况下,它们可以互换使用(主要例外是 v2.x 之前的 Python 版本,其中整数数组标量不能用作列表和元组的索引)。有一些例外,例如当代码需要非常特定的标量属性时,或者当它专门检查一个值是否是 Python 标量时。通常,通过使用相应的 Python 类型函数(例如,int、float、complex、str、unicode)将数组标量显式转换为 Python 标量,可以轻松解决问题。

使用数组标量的主要优点是它们保留了数组类型(Python 可能没有可用的匹配标量类型,例如 int16)。因此,使用数组标量可确保数组和标量之间的行为相同,而不管值是否在数组内。 NumPy 标量也有许多与数组相同的方法。

第二段写在第一段的上下文中。它试图解释为什么数组的元素是returned as array scalars。也就是说,为什么 arr[0,1] 返回 np.float32 对象,而不是 Python float

并不是建议我们直接创建array scalar

我第一次写这个答案时掩盖了 0d 数组和这句话所称的 array scalars 之间的区别。

【讨论】:

  • 非常感谢。我不知道[...] 突变。这正是我想要的——模拟单精度浮点运算的效果。
  • @Bill 对于实际的标量(如np.float32(1)),x[...] 会将其转换为 0D 数组,但x[...] = 2 将引发TypeError。尝试使用标量和 0D 数组以及 1 元素 1D 数组(以及 x[:]x[()]),直到你知道发生了什么。
  • 我稍微扩展了 0d 数组和 np.float32 对象之间的区别。 @abarnert
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-12
  • 1970-01-01
  • 2019-07-05
相关资源
最近更新 更多