【问题标题】:Numpy subarray for arbitrary number of dimension用于任意维数的 Numpy 子数组
【发布时间】:2013-11-19 11:31:59
【问题描述】:

在 Numpy 中,假设你有一个 Nd 数组 A,你可以通过 A[...,0] 对最后一个维度进行切片,或者通过A[0] 对第一个维度进行切片。我想将这个操作推广到所有维度(不仅仅是第一个或最后一个),我希望它适用于任意 N 的 Nd 数组,这样如果 A3 是 3d 数组而 A4 是 4d 数组,func(A3, dim = 1, slice = 0) 给我@ 987654324@和func(A4, dim = 1, slice = 0)给我A4[ : , 0 , : , : ]

我已经寻找了一段时间,终于想出了如何在不做可怕的黑客攻击的情况下做到这一点(比如交换维度,直到感兴趣的维度位于最后一个位置)。所以我在这里发布的代码可以满足我的需要,但是

1) 我一直在寻求让自己变得更好的建议

2) 正如我所说,我已经寻找了一段时间,但从未找到任何东西,因此它可能对其他人有用。

def fancy_subarray(farray, fdim, fslice):
    # Return the farray slice at position fslice in dimension fdim

    ndim = farray.ndim

    # Handle negative dimension and slice indexing
    if fdim < 0:
        fdim += ndim
    if fslice < 0:
        fslice += v.shape[fdim]

    # Initilize slicing tuple
    obj = ()

    for i in range(ndim):
        if i == fdim:
            # Only element fslice in that dimension
            obj += (slice(fslice, fslice+1, 1),)
        else:
            # "Full" dimension
            obj += (slice(None,None,1),)

    return farray[obj].copy()

所以这个小函数只是通过连接我们不想切片的维度位置的slice(None,None,1)和感兴趣的维度的slice(fslice, fslice+1, 1)来构建一个切片元组。它比返回一个子数组。它处理负索引。

这与直接索引略有不同:如果 A3 为 3x4x5,A3[:,0,:] 将是 3x5,而fancy_subarray(A3, fdim = 1, fslice = 0) 将是 3x1x5。该函数还“自然地”处理超出范围的维度和索引。如果fdim &gt;= farray.ndim 函数只返回完整数组,因为for 循环内的if 条件永远不会为真,如果fslice &gt;= farray.shape[fdim] 返回的子数组在维度fdim 中的大小为0。

当然,这可以很容易地扩展到不仅仅是在一维中选择一个元素。

谢谢!

【问题讨论】:

    标签: numpy multidimensional-array slice matrix-indexing


    【解决方案1】:

    我认为您将事情复杂化了,尤其是在处理fslice 时。如果你只是这样做:

    def fancy_subarray(farray, fdim, fslice):
        fdim += farray.ndim if fdim < 0 else 0
        index = ((slice(None),) * fdim + (fslice,) +
                 (slice(None),) * (farray.ndim - fdim - 1))
        return farray[index]
    

    那么您不仅可以使代码更紧凑,而且相同的函数可以采用单个索引、切片甚至索引列表:

    >>> fancy_subarray(a, 1, 2)
    array([[10, 11, 12, 13, 14],
           [30, 31, 32, 33, 34],
           [50, 51, 52, 53, 54]])
    >>> fancy_subarray(a, 1, slice(2,3))
    array([[[10, 11, 12, 13, 14]],
    
           [[30, 31, 32, 33, 34]],
    
           [[50, 51, 52, 53, 54]]])
    >>> fancy_subarray(a, 1, [2, 3])
    array([[[10, 11, 12, 13, 14],
            [15, 16, 17, 18, 19]],
    
           [[30, 31, 32, 33, 34],
            [35, 36, 37, 38, 39]],
    
           [[50, 51, 52, 53, 54],
            [55, 56, 57, 58, 59]]])
    

    【讨论】:

    • 太棒了!比我的 for 循环构造索引要好得多。我还看到您删除了 .copy(),切片通常不只返回数组上的视图吗?
    猜你喜欢
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-15
    • 2020-06-06
    • 1970-01-01
    相关资源
    最近更新 更多