1

在 Numpy 中,假设您有一个 Nd 数组 A,您可以通过 do 对最后一个维度进行切片,也A[...,0]可以通过 do 对第一个维度进行切片A[0]。我想将这个操作推广到所有维度(不仅仅是第一个或最后一个),我希望这个操作适用于任意 N 的 Nd 数组,这样如果 A3 是 3d 数组而 A4 是 4d 数组,func(A3, dim = 1, slice = 0)给我A3[ : , 0 , :]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 >= farray.ndim函数只返回完整数组,因为 for 循环内的 if 条件永远不会为真,并且fslice >= farray.shape[fdim]返回的子数组在维度 fdim 中的大小为 0。

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

谢谢!

4

1 回答 1

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]]])
于 2013-11-07T17:54:52.690 回答