可以在numpy中形成ndarray对角线的视图

时间:2016-09-15 15:51:25

标签: python numpy

简单切片形成父数组的视图。视图的步幅通常是父数组步长的倍数。

给定带有步幅(s0, s1)的2d父数组,带有步幅(s0+s1)的1D数组给出父数组对角线的视图。

有没有办法在顶级Python / numpy中创建这样的视图?提前谢谢。

3 个答案:

答案 0 :(得分:2)

使用as_strided我可以做你想做的事:

In [298]: X=np.eye(5)
In [299]: X.strides
Out[299]: (40, 8)
In [300]: np.lib.stride_tricks.as_strided(X,shape=(5,),strides=(48,))
Out[300]: array([ 1.,  1.,  1.,  1.,  1.])

虽然有些人认为as_strided离“胆量”更近了一步。比大多数numpy Python代码。

我可以通过对展平数组进行索引来实现同样的跨越:

In [311]: X.ravel()[::6]
Out[311]: array([ 1.,  2.,  3.,  4.,  5.]) 

(此处X值已通过view测试更改。

答案 1 :(得分:2)

如果您使用的是numpy 1.9或更高版本,并且只读视图就足够了,您可以使用numpy.diagonal。文档字符串表示在numpy的某个未来版本中,numpy.diagonal将返回读/写视图,但这对您现在没有帮助。如果您需要读/写视图,@ hpaulj建议使用as_strided将起作用。我建议像

这样的东西
diag = as_strided(a, shape=(min(a.shape),), strides=(sum(a.strides),))

请务必阅读as_strided docstring的“注释”部分。

答案 2 :(得分:0)

对于适用于2个以上维度的版本:

import numpy as np


def diagonal_view(array, axis1=0, axis2=1):
    """Return a view of the array diagonal."""
    assert array.ndim >= 2
    axis1, axis2 = min([axis1, axis2]), max([axis1, axis2])
    shape = list(array.shape)
    new = min([shape[axis1], shape[axis2]])
    shape.pop(axis1)
    shape.pop(axis2 - 1)
    shape.append(new)
    strides = list(array.strides)
    new = strides[axis1] + strides[axis2]
    strides.pop(axis1)
    strides.pop(axis2 - 1)
    strides.append(new)
    diag = np.lib.stride_tricks.as_strided(array, shape=shape, strides=strides)
    return diag


def test_diagonal_view():
    # test correspondence with np.diagonal
    for array in [
            np.random.randn(10, 4),
            np.random.randn(10, 4).T,
            np.random.randn(10, 4, 8),
            np.random.randn(10, 4, 8).T,
            np.random.randn(10, 4, 8).swapaxes(0, 1),
            np.random.randn(3, 4, 8, 5),
            np.random.randn(3, 4, 8, 5).swapaxes(0, 2),
    ]:
        for axis1 in range(array.ndim):
            for axis2 in range(array.ndim):
                if axis1 != axis2:
                    result = diagonal_view(array, axis1=axis1, axis2=axis2)
                    # compare with np.diagonal
                    reference = np.diagonal(array, axis1=axis1, axis2=axis2)
                    np.testing.assert_array_equal(result, reference)
                    # test that this is a modifiable view
                    result += 1
                    reference = np.diagonal(array, axis1=axis1, axis2=axis2)
                    np.testing.assert_array_equal(result, reference)


test_diagonal_view()