Python 最小尺寸的包围Numpy阵列(裁剪)

Python 最小尺寸的包围Numpy阵列(裁剪),python,arrays,numpy,scipy,Python,Arrays,Numpy,Scipy,我想在包含满足条件的所有值的数据数组中找到最小大小的二维数据数组 例如: 假设我有数组 x = np.array([[1, 1, 5, 3, 11, 1], [1, 2, 15, 19, 21, 33], [1, 8, 17, 22, 21, 31], [3, 5, 6, 11, 23, 19]]) 并调用f(x,x%2==0) 那么程序的返回值就是数组 [[2, 15, 19] [8, 17, 22] [5, 6, 11]] 因为它是包含所有偶数的最小矩形数组

我想在包含满足条件的所有值的数据数组中找到最小大小的二维数据数组

例如: 假设我有数组

x = np.array([[1, 1, 5, 3, 11, 1],
    [1, 2, 15, 19, 21, 33],
    [1, 8, 17, 22, 21, 31],
    [3, 5, 6,  11, 23, 19]])
并调用
f(x,x%2==0)
那么程序的返回值就是数组

[[2, 15, 19]
 [8, 17, 22]
 [5, 6, 11]]
因为它是包含所有偶数的最小矩形数组(条件)

我找到了一种方法,通过使用
np.argwhere
找到条件为真的所有索引,然后从原始数组中从最小索引到最大索引进行切片,我使用了
for循环
,但我想知道是否有更有效的方法使用numpy或scipy

我目前的方法是:

def f(arr, cond_arr):
    indices = np.argwhere(cond_arr)
    min = np.amin(indices, axis = 0) #get first row, col meeting cond
    max = np.amax(indices, axis = 0) #get last row, col meeting cond
    return arr[min[0]:max[0] + 1, min[1] : max[1] + 1]

这个函数已经相当有效了,但是你可以做得更好

我们不必检查每行/每列的条件,然后查找最小值和最大值,而是可以将条件折叠到每个轴中(使用逻辑OR进行缩减),然后查找第一个/最后一个索引:

def f2(arr, cond_arr):
    c0 = np.where(np.logical_or.reduce(cond_arr, axis=0))[0]
    c1 = np.where(np.logical_or.reduce(cond_arr, axis=1))[0]    
    return arr[c0[0]:c0[-1] + 1, c1[0]:c1[-1] + 1]
工作原理:

对于示例数据
cond_array
,如下所示:

>>> (x%2==0).astype(int)
array([[0, 0, 0, 0, 0, 0],
       [0, 1, 0, 0, 0, 0],
       [0, 1, 0, 1, 0, 0],
       [0, 0, 1, 0, 0, 0]])
以下是列条件:

>>> np.logical_or.reduce(cond_arr, axis=0).astype(int)
array([0, 1, 1, 1, 0, 0])
>>> np.logical_or.reduce(cond_arr, axis=).astype(int)
array([0, 1, 1, 1])
这是行的条件:

>>> np.logical_or.reduce(cond_arr, axis=0).astype(int)
array([0, 1, 1, 1, 0, 0])
>>> np.logical_or.reduce(cond_arr, axis=).astype(int)
array([0, 1, 1, 1])
现在我们只需要为两个数组中的每一个找到第一个/最后一个非零元素

真的快吗

%timeit f(x, x%2 == 0)   #  10000 loops, best of 3: 24.6 µs per loop
%timeit f2(x, x%2 == 0)  # 100000 loops, best of 3: 12.6 µs per loop
嗯,有一点。。。但在更大的阵列中,它确实非常出色:

x = np.random.randn(1000, 1000)
c = np.zeros((1000, 1000), dtype=bool)
c[400:600, 400:600] = True

%timeit f(x,c)   #  100 loops, best of 3: 5.28 ms per loop
%timeit f2(x,c)  # 1000 loops, best of 3: 225 µs per loop
最后,此版本的开销稍大,但在维度数量上是通用的:

def f3(arr, cond_arr):
    s = []
    for a in range(arr.ndim):
        c = np.where(np.logical_or.reduce(cond_arr, axis=a))[0]
        s.append(slice(c[0], c[-1] + 1))
    return arr[s]

依我看,你的职能已经相当有效了。对于您的需求来说,它是否太慢了?它可以很好地处理我的数据,我只是想知道是否有更好的方法,老的kolmogorov复杂性问题。Numpy优化得很好,但在应用高级索引之前,我必须调用3次完整数组比较。我觉得有一个函数可以在数组的一次遍历中同时找到最小和最大索引。