检查一个numpy数组的所有边界是否都为0 [关闭]


13

检查多维numpy数组的所有面是否都为0的最快方法是什么?

因此,对于一个简单的2D示例,我有:

x = np.random.rand(5, 5)
assert np.sum(x[0:,  0]) == 0
assert np.sum(x[0,  0:]) == 0
assert np.sum(x[0:, -1]) == 0
assert np.sum(x[-1, 0:]) == 0

虽然这对于正确的2D案例来说是可以的,但是为更大的尺寸编写代码有点乏味,我想知道是否可以使用一些聪明的numpy技巧来使它高效且可维护。


8
np.all (x[:, 0] == 0)比总和更安全吗?仅当所有数字均为正时,总和检验才正确。
Demi-Lune


1
@ Demi-Lume很有道理。就我而言,一切都会> = 0,但您的评论会受到感激:)

1
在3D情况下,您是指立方体的面(有六个)还是边(有十二个)?
Riccardo Bucco

@RiccardoBucco是的,有6张脸。但我的问题是,它可以去更高维度大于3
卢卡

Answers:


7

方法如下:

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

np.take 与“花式”索引功能相同。


1
@Luca:文档没有明确说明,但numpy.take会进行复制。这可能导致它的性能比基于视图的代码差。(必须确定时间
-NumPy的

1
@RiccardoBucco:len(x.shape)可以更简单地写为x.ndim
user2357112支持Monica

1
@ user2357112supportsMonica谢谢,我已解决它:)
Riccardo Bucco

5
另外,使用列表理解还可以防止all短路。您可以删除方括号以使用生成器表达式,从而允许all在一次numpy.all调用返回时立即返回False
user2357112支持Monica

1
@ user2357112supports莫妮卡真实!!
Riccardo Bucco

5

这是一个实际上检查您感兴趣的数组部分的答案,并且不会浪费时间来构造整个数组大小的蒙版。有一个Python级循环,但是很短,迭代与维数成正比,而不是数组的大小成比例。

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

有什么情况not (view[0] == 0).all()不等于view[0].any()吗?
Paul Panzer

@PaulPanzer:我想view[0].any()也可以。我不能完全确定两个选项中涉及的转换和缓冲对效率的影响- view[0].any()理论上可以更快地实现,但是我以前见过奇怪的结果,而且我还没有完全理解所涉及的缓冲。
user2357112支持Monica

我想view[0].view(bool).any()这将是高速解决方案。
Paul Panzer


(此外,无论是argmax还是any,使用布尔视图都意味着将负零视为不等于正零。)
user2357112支持Monica

2

我重塑了数组,然后遍历它。不幸的是,我的答案假设您至少具有三个维,并且对于正常矩阵会出错,因此您必须为1和2维形状的数组添加一个特殊子句。此外,这将很慢,因此可能会有更好的解决方案。

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

哪个会产生

>>> False
>>> True

基本上,我将所有尺寸堆叠在一起,然后查看它们以检查其边缘。


这将检查数组的错误部分。对于3维数组,我们要检查整个数组的面,而不是每个2维子数组的边缘。
user2357112支持Monica

嗯,这更有意义。我误会了
lwileczek

1

也许省略号运算符正是您要寻找的,它将在许多方面适用:

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)

这不会为所有面孔着色。例如,尝试使用(4,4,4)立方体。

我不确定您给脸部着色是什么意思,但是如果您使x(
4,4,4

1

您可以使用slice和布尔掩码来完成工作:

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])

此函数首先将数组的“核心”整形为元组s,然后构建True仅显示边界点的蒙版。然后,布尔索引将提供边界点。

工作示例:

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])

然后,np.all(borders==0)将为您提供所需的信息。


注意:这对于一维数组来说很困难,尽管我认为这是一个边缘情况。您最好检查一下有问题的两点


这花费的时间与数组中元素的总数成正比,而不仅仅是边框。同样,一维数组也不是无关紧要的情况。
user2357112支持Monica

1
此外,np.arange(15)不包括15
user2357112支持莫妮卡

我同意“无关紧要”的措辞很强,尽管我认为最好检查一维数组的两个相关点。15号是一个错别字,很好的捕获
Lukas Thaler
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.