简体   繁体   English

循环替换numpy数组的布尔/非零索引

[英]Alternative to loop for for boolean / nonzero indexing of numpy array

I need to select only the non-zero 3d portions of a 3d binary array (or alternatively the true values of a boolean array). 我只需要选择3d二进制数组的非零3d部分(或者布尔数组的真实值)。 Currently I am able to do so with a series of 'for' loops that use np.any, but this does work but seems awkward and slow, so currently investigating a more direct way to accomplish the task. 目前,我可以使用一系列使用np.any的“ for”循环来做到这一点,但这确实可行,但似乎很尴尬且缓慢,因此目前正在研究一种更直接的方法来完成任务。

I am rather new to numpy, so the approaches that I have tried include a) using np.nonzero , which returns indices that I am at a loss to understand what to do with for my purposes, b) boolean array indexing , and c) boolean masks . 我对numpy相当陌生,因此我尝试过的方法包括:a)使用np.nonzero ,该方法返回我不知所措的索引,以了解要达到的目的,b) 布尔数组索引 ,以及c) 布尔口罩 I can generally understand each of those approaches for simple 2d arrays, but am struggling to understand the differences between the approaches, and cannot get them to return the right values for a 3d array. 我通常可以理解简单2D数组的每种方法,但是却在努力理解这些方法之间的差异,并且无法使它们返回3D数组的正确值。

Here is my current function that returns a 3D array with nonzero values: 这是我当前的函数,该函数返回具有非零值的3D数组:

def real_size(arr3):
    true_0 = []
    true_1 = []
    true_2 = []
    print(f'The input array shape is: {arr3.shape}')

    for zero_ in range (0, arr3.shape[0]):
        if arr3[zero_].any()==True:
            true_0.append(zero_)
    for one_ in range (0, arr3.shape[1]):
        if arr3[:,one_,:].any()==True:
            true_1.append(one_)
    for two_ in range (0, arr3.shape[2]):
        if arr3[:,:,two_].any()==True:
            true_2.append(two_)

    arr4 = arr3[min(true_0):max(true_0) + 1, min(true_1):max(true_1) + 1, min(true_2):max(true_2) + 1]
    print(f'The nonzero area is: {arr4.shape}')
    return arr4

# Then use it on a small test array:
test_array = np.zeros([2, 3, 4], dtype = int)
test_array[0:2, 0:2, 0:2] = 1

#The function call works and prints out as expected:
non_zero = real_size(test_array)
>> The input array shape is: (2, 3, 4) 
>> The nonzero area is: (2, 2, 2)

# So, the array is correct, but likely not the best way to get there:
non_zero

>> array([[[1, 1],
        [1, 1]],

       [[1, 1],
        [1, 1]]])

The code works appropriately, but I am using this on much larger and more complex arrays, and don't think this is an appropriate approach. 该代码可以正常工作,但是我在更大,更复杂的数组上使用了它,并且认为这不是合适的方法。 Any thoughts on a more direct method to make this work would be greatly appreciated. 任何对采用更直接的方法进行这项工作的想法将不胜感激。 I am also concerned about errors and the results if the input array has for example two separate non-zero 3d areas within the original array. 如果输入数组例如在原始数组内有两个单独的非零3d区域,我也会担心错误和结果。

To clarify the problem, I need to return one or more 3D portions as one or more 3d arrays beginning with an original larger array. 为了阐明问题,我需要将一个或多个3D部分作为一个或多个3d数组(以原始的较大数组开头)返回。 The returned arrays should not include extraneous zeros (or false values) in any given exterior plane in three dimensional space. 返回的数组不应在三维空间中任何给定的外部平面中包含无关的零(或假值)。 Just getting the indices of the nonzero values (or vice versa) doesn't by itself solve the problem. 仅获取非零值的索引(反之亦然)本身并不能解决问题。

Assuming you want to eliminate all rows, columns, etc. that contain only zeros, you could do the following: 假设您要消除包含零的所有行,列等,则可以执行以下操作:

nz = (test_array != 0)
non_zero = test_array[nz.any(axis=(1, 2))][:, nz.any(axis=(0, 2))][:, :, nz.any(axis=(0, 1))]

An alternative solution using np.nonzero : 使用np.nonzero的替代解决方案:

i = [np.unique(_) for _ in np.nonzero(test_array)]
non_zero = test_array[i[0]][:, i[1]][:, :, i[2]]

This can also be generalized to arbitrary dimensions, but requires a bit more work (only showing the first approach here): 也可以将其推广到任意尺寸,但是需要做更多的工作(此处仅显示第一种方法):

def real_size(arr):
    nz = (arr != 0)
    result = arr
    axes = np.arange(arr.ndim)
    for axis in range(arr.ndim):
        zeros = nz.any(axis=tuple(np.delete(axes, axis)))
        result = result[(slice(None),)*axis + (zeros,)]
    return result

non_zero = real_size(test_array)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM