numpy矩阵跟踪行为

时间:2014-02-09 20:51:06

标签: numpy matrix

如果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的发行说明中没有看到任何内容发生变化。

2 个答案:

答案 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)

meanprod等也是如此。如果_collapseaxis,则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代码库不太熟悉,无法准确地弄明白。

  • np.trace和ndarray.trace是两个不同的功能。
    • np.trace在“core / fromnumeric.py”
    • 中定义
    • ndarray.trace在“core / src / multiarray / methods.c或calculation.c”中定义。
  • np.trace将对象转换为ndarray
  • ndarray.trace将尝试将对象保留为子类对象。
    • 对此不确定,我不明白该代码的深蹲tbh

两个跟踪函数都会将结果保存为数组对象(子类或非子类)。如果它是单个值,它将返回该单个值,否则它将返回数组对象。

由于结果保留为矩阵对象,因此上面的函数将强制它为二维。因此,它不会作为单个值返回,而是作为矩阵对象返回。

通过编辑_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