为什么 Numpy 中的 0d 数组不被视为标量?
- 2025-03-20 08:47:00
- admin 原创
- 43
问题描述:
0d 数组肯定是标量,但 Numpy 似乎并不这么认为...是我遗漏了什么还是我只是误解了这个概念?
>>> foo = numpy.array(1.11111111111, numpy.float64)
>>> numpy.ndim(foo)
0
>>> numpy.isscalar(foo)
False
>>> foo.item()
1.11111111111
解决方案 1:
大家不必想太多。这最终对个人的心理健康和寿命更有利。
Numpy 标量类型的奇怪情况源于这样一个事实:没有优雅而一致的方法将 1x1 矩阵降级为标量类型。尽管从数学上讲它们是同一件事,但它们由非常不同的代码处理。
如果您编写过大量科学代码,最终您会希望能够max(a)
处理各种大小的矩阵,甚至是标量。从数学上讲,这是完全合理的。但是对于程序员来说,这意味着 Numpy 中表示标量的任何内容都应该具有 .shape 和 .ndim 属性,因此至少 ufuncs 不必针对 Numpy 中 21 种可能的标量类型对其输入进行显式类型检查。
另一方面,它们还应该与现有的对标量类型进行显式类型检查的 Python 库一起使用。这是一个两难的境地,因为 Numpy ndarray 在被简化为标量时必须单独更改其类型,并且如果不对所有访问进行检查,就无法知道是否发生了这种情况。实际上,按照标量类型标准,采用这种方式可能会使工作速度变得非常慢。
Numpy 开发人员的解决方案是从 ndarray 和 Python 标量继承其自己的标量类型,这样所有标量也都有 .shape、.ndim、.T 等。1x1 矩阵仍将存在,但如果你知道你将处理标量,则不鼓励使用它。虽然这在理论上应该可以正常工作,但偶尔你仍然可以看到他们用油漆滚筒遗漏的一些地方,丑陋的内部结构暴露在众人面前:
>>> from numpy import *
>>> a = array(1)
>>> b = int_(1)
>>> a.ndim
0
>>> b.ndim
0
>>> a[...]
array(1)
>>> a[()]
1
>>> b[...]
array(1)
>>> b[()]
1
确实没有理由这样做a[...]
,也a[()]
应该返回不同的东西,但事实确实如此。有提案要改变这一点,但看起来他们忘了完成 1x1 数组的工作。
一个可能更大、也可能无法解决的问题是 Numpy 标量是不可变的。因此,将标量“喷射”到 ndarray 中(从数学上讲,将数组折叠为标量的伴随操作)是一个 PITA 实现。您实际上无法增大 Numpy 标量,根据定义,它不能被转换为 ndarray,尽管newaxis
它可以神秘地工作:
>>> b[0,1,2,3] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'numpy.int32' object does not support item assignment
>>> b[newaxis]
array([1])
在 Matlab 中,增加标量的大小是完全可以接受的、无需动脑的操作。而在 Numpy 中,你必须坚持使用a = array(a)
你认为可能以标量开始并以数组结束的任何地方。我理解为什么 Numpy 必须这样才能与 Python 很好地兼容,但这并不能改变许多新转换者对此深感困惑的事实。有些人清楚地记得自己曾与这种行为作斗争并最终坚持下来,而其他走得太远的人通常会留下一些深深的、无形的精神伤疤,这些伤疤经常困扰着他们最天真的梦想。这对所有人来说都是一个糟糕的情况。
解决方案 2:
您必须以稍微不同的方式创建标量数组:
>>> x = numpy.float64(1.111)
>>> x
1.111
>>> numpy.isscalar(x)
True
>>> numpy.ndim(x)
0
从纯数学的角度来看, numpy 中的标量似乎与您习惯的概念略有不同。我猜您是在考虑标量矩阵?
扫码咨询,免费领取项目管理大礼包!