75

一个 0d 数组肯定是标量,但 Numpy 似乎不这么认为......我错过了什么还是我只是误解了这个概念?

>>> foo = numpy.array(1.11111111111, numpy.float64)
>>> numpy.ndim(foo)
0
>>> numpy.isscalar(foo)
False
>>> foo.item()
1.11111111111
4

2 回答 2

153

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

Numpy 标量类型的奇怪情况是因为没有优雅且一致的方法将 1x1 矩阵降级为标量类型。尽管在数学上它们是相同的东西,但它们是由非常不同的代码处理的。

如果您一直在编写任何数量的科学代码,最终您会想要max(a)处理各种大小的矩阵,甚至是标量。从数学上讲,这是一件完全合情合理的事情。然而,对于程序员来说,这意味着在 Numpy 中呈现的任何标量都应该具有 .shape 和 .ndim 属性,因此至少 ufunc 不必针对 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 中,增加标量的大小是完全可以接受且无需脑力的操作。a = array(a)在 Numpy 中,您必须在任何您认为可能以标量开始并以数组结尾的地方都坚持使用 jarring 。我理解为什么 Numpy 必须以这种方式与 Python 配合得很好,但这并不能改变许多新切换器对此深感困惑的事实。有些人清楚地记得与这种行为作斗争并最终坚持下去,而另一些离得太远的人通常会留下一些深深的无形的精神伤疤,经常困扰着他们最天真的梦想。这对所有人来说都是一个丑陋的情况。

于 2009-04-27T18:55:32.490 回答
6

您必须稍微不同地创建标量数组:

>>> x = numpy.float64(1.111)
>>> x
1.111
>>> numpy.isscalar(x)
True
>>> numpy.ndim(x)
0

从纯数学的角度来看,numpy 中的标量看起来可能与您可能习惯的概念有点不同。我猜你在考虑标量矩阵?

于 2009-04-21T15:20:27.110 回答