Check if all sides of a multidimensional numpy array are arrays of zeros

前端 未结 5 1498
青春惊慌失措
青春惊慌失措 2021-02-13 16:55

An n-dimensional array has 2n sides (a 1-dimensional array has 2 endpoints; a 2-dimensional array has 4 sides or edges; a 3-dimensional array has 6 2-dimensional faces; a 4-dime

相关标签:
5条回答
  • 2021-02-13 17:14

    Here's how you can do it:

    assert(all(np.all(np.take(x, index, axis=axis) == 0)
               for axis in range(x.ndim)
               for index in (0, -1)))
    

    np.take does the same thing as "fancy" indexing.

    0 讨论(0)
  • 2021-02-13 17:16

    I reshaped the array and then iterated through it. Unfortunately, my answer assumes you have at least three dimensions and will error out for normal matrices, you would have to add a special clause for 1 & 2 dimensional shaped arrays. In addition, this will be slow so there are likely better solutions.

    x = np.array(
            [
                [
                    [0 , 1, 1, 0],
                    [0 , 2, 3, 0],
                    [0 , 4, 5, 0]
                ],
                [
                    [0 , 6, 7, 0],
                    [0 , 7, 8, 0],
                    [0 , 9, 5, 0]
                ]
            ])
    
    xx = np.array(
            [
                [
                    [0 , 0, 0, 0],
                    [0 , 2, 3, 0],
                    [0 , 0, 0, 0]
                ],
                [
                    [0 , 0, 0, 0],
                    [0 , 7, 8, 0],
                    [0 , 0, 0, 0]
                ]
            ])
    
    def check_edges(x):
    
        idx = x.shape
        chunk = np.prod(idx[:-2])
        x = x.reshape((chunk*idx[-2], idx[-1]))
        for block in range(chunk):
            z = x[block*idx[-2]:(block+1)*idx[-2], :]
            if not np.all(z[:, 0] == 0):
                return False
            if not np.all(z[:, -1] == 0):
                return False
            if not np.all(z[0, :] == 0):
                return False
            if not np.all(z[-1, :] == 0):
                return False
    
        return True
    

    Which will produce

    >>> False
    >>> True
    

    Basically I stack all the dimensions on top of each other and then look through them to check their edges.

    0 讨论(0)
  • 2021-02-13 17:18

    You can make use of slice and boolean masking to get the job done:

    def get_borders(arr):
        s=tuple(slice(1,i-1) for i in a.shape)
        mask = np.ones(arr.shape, dtype=bool)
        mask[s] = False
        return(arr[mask])
    

    This function first shapes the "core" of the array into the tuple s, and then builds a mask that shows True only for the bordering points. Boolean indexing then delivers the border points.

    Working example:

    a = np.arange(16).reshape((4,4))
    
    print(a)
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11],
           [12, 13, 14, 15]])
    
    borders = get_borders(a)
    print(borders)
    array([ 0,  1,  2,  3,  4,  7,  8, 11, 12, 13, 14, 15])
    

    Then, np.all(borders==0) will give you the desired information.


    Note: this breaks for one-dimensional arrays, though I consider those an edge case. You're probably better off just checking the two points in question there

    0 讨论(0)
  • 2021-02-13 17:23

    Here's an answer that actually examines the parts of the array you're interested in, and doesn't waste time constructing a mask the size of the whole array. There's a Python-level loop, but it's short, with iterations proportional to the number of dimensions instead of the array's size.

    def all_borders_zero(array):
        if not array.ndim:
            raise ValueError("0-dimensional arrays not supported")
        for dim in range(array.ndim):
            view = numpy.moveaxis(array, dim, 0)
            if not (view[0] == 0).all():
                return False
            if not (view[-1] == 0).all():
                return False
        return True
    
    0 讨论(0)
  • 2021-02-13 17:31

    maybe the ellipsis operator is what you are looking for, which will work for many dimensions:

    import numpy as np
    
    # data
    x = np.random.rand(2, 5, 5)
    x[..., 0:, 0] = 0
    x[..., 0, 0:] = 0
    x[..., 0:, -1] = 0
    x[..., -1, 0:] = 0
    
    test = np.all(
        [
            np.all(x[..., 0:, 0] == 0),
            np.all(x[..., 0, 0:] == 0),
            np.all(x[..., 0:, -1] == 0),
            np.all(x[..., -1, 0:] == 0),
        ]
    )
    
    print(test)
    
    0 讨论(0)
提交回复
热议问题