如果X是NumPy matrix
对象,为什么np.trace(X)
会返回标量(如预期的那样),但X.trace()
会返回1x1
matrix
个对象?< / p>
>>> X = np.matrix([[1, 2], [3, 4]])
>>> np.trace(X)
5
>>> X.trace()
matrix([[5]]) # Why not just 5, which would be more useful?
我正在使用NumPy 1.7.1,但在1.8的发行说明中没有看到任何内容发生变化。
答案 0 :(得分:2)
因为X.trace
是这样编码的! matrix
文档说:
矩阵是一种专用的二维阵列,保留了它的二维特性 通过运营。
np.trace
编码为(使用ndarray.trace
):
return asarray(a).trace(offset, axis1, axis2, dtype, out)
如何评估矩阵迹线是很难的。但是看https://github.com/numpy/numpy/blob/master/numpy/matrixlib/defmatrix.py
我怀疑它等同于:
np.asmatrix(X.A.trace())
在同一个文件中,sum
定义为:
return N.ndarray.sum(self, axis, dtype, out, keepdims=True)._collapse(axis)
mean
,prod
等也是如此。如果_collapse
为axis
,则None
会返回标量。矩阵trace
没有明确的定义,因此它可能使用__array_finalize__
。换句话说,trace
会返回默认的matrix
类型。
返回标量的几个结构是:
X.A.trace()
X.diagonal().sum()
X.trace()._collapse(None)
答案 1 :(得分:2)
def __array_finalize__(self, obj):
self._getitem = False
if (isinstance(obj, matrix) and obj._getitem): return
ndim = self.ndim
if (ndim == 2):
return
if (ndim > 2):
newshape = tuple([x for x in self.shape if x > 1])
ndim = len(newshape)
if ndim == 2:
self.shape = newshape
return
elif (ndim > 2):
raise ValueError("shape too large to be a matrix.")
else:
newshape = self.shape
if ndim == 0:
self.shape = (1, 1)
elif ndim == 1:
self.shape = (1, newshape[0])
return
这是来自矩阵定义,子类化ndarray。跟踪功能没有改变,因此它实际上是被调用的相同功能。
每次创建矩阵对象时都会调用此函数。问题是如果ndims小于2,则强制它更大。
接下来是一些有根据的猜测工作,我认为这应该是正确的,但我对numpy代码库不太熟悉,无法准确地弄明白。
两个跟踪函数都会将结果保存为数组对象(子类或非子类)。如果它是单个值,它将返回该单个值,否则它将返回数组对象。
由于结果保留为矩阵对象,因此上面的函数将强制它为二维。因此,它不会作为单个值返回,而是作为矩阵对象返回。
通过编辑_array_finalize__
函数进一步支持这一结论:
def __array_finalize__(self, obj):
self._getitem = False
if (isinstance(obj, matrix) and obj._getitem): return
ndim = self.ndim
if (ndim == 2):
return
if (ndim > 2):
newshape = tuple([x for x in self.shape if x > 1])
ndim = len(newshape)
if ndim == 2:
self.shape = newshape
return
elif (ndim > 2):
raise ValueError("shape too large to be a matrix.")
else:
newshape = self.shape
return
if ndim == 0:
self.shape = (1, 1)
elif ndim == 1:
self.shape = (1, newshape[0])
return
在最后一次if-else检查之前注意新的return
。现在,X.trace()的结果是单个值。
这不是固定,如果您自己尝试,请恢复更改。
他们有很好的理由这样做
np.trace
没有这个问题,因为它直接将它转换为数组对象。
np.trace
的代码是(没有docstring):
def trace(a, offset=0, axis1=0, axis2=1, dtype=None, out=None):
return asarray(a).trace(offset, axis1, axis2, dtype, out)
来自asarray
a
的数组解释。如果输入,则不执行复制 已经是一个ndarray。 如果a
是ndarray的子类,则为基数 返回类ndarray 。