如何使用掩码仅替换 numpy 数组的零

a.s*_*iet 5 python numpy

考虑一个二维数组:

arr = np.zeros((10,10))
arr[3:7,3:7] = 1
Run Code Online (Sandbox Code Playgroud)

现在我想使用掩码将其中的一部分替换为其他值:

mask = np.ones((5,5)).astype(bool)
arr[5:,5:][mask] = 2
Run Code Online (Sandbox Code Playgroud)

是否可以保留原始文件中的非零元素arr并使用掩码仅替换零元素?我想避免通过平面索引来这样做,因为我处理的数组是大型 3D 数组(大约 1000x1000x1000)。

编辑:一些附加信息:

我想避免更改掩码,这包括在数组非零的情况下将其设置为 False 以及调整其大小。原因是该操作需要重复多次,并将掩模放置在阵列的不同区域。由于数组非常大,因此最好避免复制数据。

hpa*_*ulj 1

其他人建议logical_and,但你反对,因为它涉及太多复制。但首先让我们建立一个交互式案例来执行此操作

In [353]: arr=np.zeros((10,10))
In [354]: arr[3:7,3:7]=1

In [355]: tups=[(slice(5),slice(5)),
                (slice(0,5),slice(3,8)),
                (slice(4,9),slice(1,6))]

In [356]: for i,tup in enumerate(tups):
    mask1=np.logical_and(mask,arr[tup]==0)
    arr[tup][mask1]=i+1
   .....:     

In [357]: arr
Out[357]: 
array([[ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  2.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  2.,  0.,  0.],
       [ 0.,  3.,  3.,  1.,  1.,  1.,  1.,  0.,  0.,  0.],
       [ 0.,  3.,  3.,  1.,  1.,  1.,  1.,  0.,  0.,  0.],
       [ 0.,  3.,  3.,  3.,  3.,  3.,  0.,  0.,  0.,  0.],
       [ 0.,  3.,  3.,  3.,  3.,  3.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]])
Run Code Online (Sandbox Code Playgroud)

arr[tup]==0是另一个面具。numpy这是您可以知道您只对更改 0 感兴趣的唯一方法。它不会自动将 0 与 1 或 3 区别对待。我没有看到任何方法可以logical_and在每个步骤中创建新的蒙版。


布尔掩码的应用确实涉及平面索引 - 也就是说,结果是一维数组(无论是在右侧还是左侧)

查看应用上次迭代中的蒙版的结果

In [360]: arr[tup][mask]
Out[360]: 
array([ 1.,  1.,  1.,  1.,  1.,  3.,  3.,  1.,  1.,  1.,  3.,  3.,  1.,
        1.,  1.,  3.,  3.,  3.,  3.,  3.,  3.,  3.,  3.,  3.,  3.])

In [361]: arr[tup][mask1]
Out[361]: array([ 3.,  3.,  3.,  3.,  3.,  3.,  3.,  3.,  3.,  3.,  3.,  3.,  3.,  3.])
Run Code Online (Sandbox Code Playgroud)

这是使用的替代方法np.where

for i,tup in enumerate(tups):
    arr[tup]=np.where(arr[tup]==0,i+1,arr[tup])
Run Code Online (Sandbox Code Playgroud)

这更简洁,但arr[tup]每次都需要写入整个切片。

In [374]: %%timeit arr=np.zeros((10,10),int);arr[3:7,3:7]=1
   .....: for i,tup in enumerate(tups):
    arr[tup]=np.where(arr[tup]==0,i+1,arr[tup])
   .....: 
1000 loops, best of 3: 134 us per loop

In [375]: %%timeit arr=np.zeros((10,10),int);arr[3:7,3:7]=1
   .....: for i,tup in enumerate(tups):
    mask1=np.logical_and(mask,arr[tup]==0)
    arr[tup][mask1]=i+1p
   .....: 
10000 loops, best of 3: 64.9 us per loop
Run Code Online (Sandbox Code Playgroud)

警告,使用时arr[tup][mask]=...arr[tup]必须是视图,例如通过切片产生的。其他索引会生成一个副本,该副本会阻止对原始数组的更改。