NumPy中的N-D索引(默认值)

3

我能够使用默认值来索引 NumPy N-D数组吗? 以下是示例代码,用于一些虚构的 np.get_with_default(a, indexes, default)

import numpy as np
print(np.get_with_default(
    np.array([[1,2,3],[4,5,6]]), # N-D array
    [(np.array([0, 0, 1, 1, 2, 2]), np.array([1, 2, 2, 3, 3, 5]))], # N-tuple of indexes along each axis
    13, # Default for out-of-bounds fallback
))

应该打印

[2 3 6 13 13 13]

我正在寻找一些内置函数来实现这个功能。如果不存在这样的函数,那么至少需要一个简短高效的实现方法。


np.take 进行某种边界测试。 - hpaulj
3个回答

2

我之所以提出这个问题,是因为我正在寻找完全相同的答案。我想到了下面的函数,它可以在二维平面上实现你所要求的功能。很可能可以将其推广到N维空间。

def get_with_defaults(a, xx, yy, nodata):
   # get values from a, clipping the index values to valid ranges
   res = a[np.clip(yy, 0, a.shape[0] - 1), np.clip(xx, 0, a.shape[1] - 1)]
   # compute a mask for both x and y, where all invalid index values are set to true
   myy = np.ma.masked_outside(yy, 0, a.shape[0] - 1).mask
   mxx = np.ma.masked_outside(xx, 0, a.shape[1] - 1).mask
   # replace all values in res with NODATA, where either the x or y index are invalid
   np.choose(myy + mxx, [res, nodata], out=res)
   return res

xxyy是索引数组,a(y,x)索引。

这给出了:

>>> a=np.zeros((3,2),dtype=int)
>>> get_with_defaults(a, (-1, 1000, 0, 1, 2), (0, -1, 0, 1, 2), -1)
array([-1, -1,  0,  0, -1])

作为替代方案,下面的实现方式可以实现相同的功能,并且更加简洁:
def get_with_default(a, xx, yy, nodata):
   # get values from a, clipping the index values to valid ranges
   res = a[np.clip(yy, 0, a.shape[0] - 1), np.clip(xx, 0, a.shape[1] - 1)]
   # replace all values in res with NODATA (gets broadcasted to the result array), where
   # either the x or y index are invalid
   res[(yy < 0) | (yy >= a.shape[0]) | (xx < 0) | (xx >= a.shape[1])] = nodata
   return res

谢谢!点赞,看起来是个不错的选择。 - Arty

1

我不知道NumPy是否有直接执行此操作的功能,但您始终可以自己实现。这并不特别聪明或有效,因为它需要多个高级索引操作,但确实能够满足您的需求:

import numpy as np

def get_with_default(a, indices, default=0):
    # Ensure inputs are arrays
    a = np.asarray(a)
    indices = tuple(np.broadcast_arrays(*indices))
    if len(indices) <= 0 or len(indices) > a.ndim:
        raise ValueError('invalid number of indices.')
    # Make mask of indices out of bounds
    mask = np.zeros(indices[0].shape, np.bool)
    for ind, s in zip(indices, a.shape):
        mask |= (ind < 0) | (ind >= s)
    # Only do masking if necessary
    n_mask = np.count_nonzero(mask)
    # Shortcut for the case where all is masked
    if n_mask == mask.size:
        return np.full_like(a, default)
    if n_mask > 0:
        # Ensure index arrays are contiguous so masking works right
        indices = tuple(map(np.ascontiguousarray, indices))
        for ind in indices:
            # Replace masked indices with zeros
            ind[mask] = 0
    # Get values
    res = a[indices]
    if n_mask > 0:
        # Replace values of masked indices with default value
        res[mask] = default
    return res

# Test
print(get_with_default(
    np.array([[1,2,3],[4,5,6]]),
    (np.array([0, 0, 1, 1, 2, 2]), np.array([1, 2, 2, 3, 3, 5])),
    13
))
# [ 2  3  6 13 13 13]

将接受直到有人找到NumPy内置的单个操作来解决任务。 - Arty

0

我也需要解决这个问题,但我想要一个适用于N维的解决方案。我让Markus的解决方案适用于N维,包括从比坐标指向更多维度的数组中进行选择。

def get_with_defaults(arr, coords, nodata):
    coords, shp = np.array(coords), np.array(arr.shape)
    # Get values from arr, clipping to valid ranges
    res = arr[tuple(np.clip(c, 0, s-1) for c, s in zip(coords, shp))]
    # Set any output where one of the coords was out of range to nodata
    res[np.any(~((0 <= coords) & (coords < shp[:len(coords), None])), axis=0)] = nodata
    return res


import numpy as np

if __name__ == '__main__':
    A = np.array([[1,2,3],[4,5,6]])
    B = np.array([[[1, -9],[2, -8],[3, -7]],[[4, -6],[5, -5],[6, -4]]])
    coords1 = [[0, 0, 1, 1, 2, 2], [1, 2, 2, 3, 3, 5]]
    coords2 = [[0, 0, 1, 1, 2, 2], [1, 2, 2, 3, 3, 5], [1, 1, 1, 1, 1, 1]]

    out1 = get_with_defaults(A, coords1, 13)
    out2 = get_with_defaults(B, coords1, 13)
    out3 = get_with_defaults(B, coords2, 13)

    print(out1)
    # [2, 3, 6, 13, 13, 13]
    print(out2)
    # [[ 2 -8]
    #  [ 3 -7]
    #  [ 6 -4]
    #  [13 13]
    #  [13 13]
    #  [13 13]]
    print(out3)
    # [-8, -7, -4, 13, 13, 13]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接