np.add 让我很头疼。如何使用 np.add 中的 where 选项?

np.add is giving me a headache. How do I use the where option in np.add?

我有两个从图像加载的数组,我需要添加这两个图像,即如果中心有一个像素值为1的圆,我需要在左上角添加一个像素值为2的三角形。我要设置的规则是,如果 1 已经在该索引中,它只会将像素值 2 添加到空白像素(像素值为 0)

我该怎么做?我一直在尝试使用 np.add 和 where 选项

mask_test = master_array == 0
master_array = np.add(master_array, new_pic, where = mask_test)

但它一直在搞砸,master_array 最终变成了 new_pic 而不是总和。网上搜索'where'的工作原理一直没有结果,因为大家都不举例,甚至有人说“哦,用的不多,就不细说了”。

此代码:

master_array = np.add(master_array, new_pic, where = mask_test)

给我这个:

但问题是当像素确实重叠时,我得到的像素值为 3,而不是它应该保留的值 1。

您可以简单地使用正常加法:

mask_test = master_array == 0
master_array += new_pic * mask_test

docs 中所述,如果 where 参数中的条件为假,out 数组将保留其“原始值”。这意味着如果要设置 where 参数,则需要指定函数将输出到的 out 数组。否则该函数会尝试从未初始化的数组中获取原始值,这会产生奇怪的结果。如果你乐意覆盖 master_array,你可以这样做:

np.add(master_array, new_pic, out=master_array, where=master_array == 0)

(您不需要在此处分配返回值 - 指定输出数组就足够了。)

+np.where 一起使用可能不那么令人头疼:

master_array += np.where(master_array == 0, new_pic, 0)

但是因为你只是在母版中像素值为0的情况下添加,所以一开始就不需要添加。您可以只使用 np.where 而不添加任何内容。

master_array = np.where(master_array == 0, new_pic, master_array)

np.add(或其他 ufunc)中使用 where 并不常见 - 特别是与 np.where 函数的使用相比。至少当我回答 SO 时,我强调需要包括 out

文档讨论了默认值 out=None 时的“未初始化”值。这可能不清楚,但实际上它意味着,一个由 np.empty.

创建的数组

这可能包含任何内容,例如:

In [263]: res = np.empty((5,5),int)
In [264]: res
Out[264]: 
array([[            50999536,                    0,      140274438367024,
        -6315338160082163841,      140273540789184],
       [                 161,             55839504,      140274448227440,
             140273575343728,   358094631352936090],
       [     140273564120384,      140273575343344, -7783537013977118542,
             140273543024256,      140273575343200],
       [-6522034781934541837,      140273620247296,      140273575343776,
         1387433780369843801,      140273560270848],
       [     140273561761968, -3190833100527581043,      140273563628672,
             140273561762640,                  480]])

定义初始数组:

In [265]: x1 = np.random.randint(0,5,(5,5))
In [266]: x1
Out[266]: 
array([[3, 2, 0, 1, 3],
       [3, 2, 4, 0, 3],
       [2, 3, 3, 4, 3],
       [3, 2, 0, 2, 2],
       [1, 2, 1, 1, 2]])
In [267]: x2=x1.copy()

没有 out,我们得到的值很像上面的 res。只有 x1==0 元素设置为 10:

In [268]: np.add(x1, 10, where=x1==0)
Out[268]: 
array([[51108864,        0,       10, 47780512, 51193856],
       [51213024, 51245760, 51252528,       10, 51260336],
       [51261168, 51261920, 51264176, 51298864, 51270656],
       [51271040, 51274864,       10, 51276640, 51277024],
       [51277808, 51278528, 51279104, 51284496, 51286448]])

或者我们可以将 out 设置为 np.zeros:

In [269]: np.add(x1, 10, where=x1==0, out=np.zeros((5,5),int))
Out[269]: 
array([[ 0,  0, 10,  0,  0],
       [ 0,  0,  0, 10,  0],
       [ 0,  0,  0,  0,  0],
       [ 0,  0, 10,  0,  0],
       [ 0,  0,  0,  0,  0]])

但是如果我们将它设置为 x1,或者 x1 的副本(这可能是您想要的):

In [270]: np.add(x1, 10, where=x1==0, out=x2)
Out[270]: 
array([[ 3,  2, 10,  1,  3],
       [ 3,  2,  4, 10,  3],
       [ 2,  3,  3,  4,  3],
       [ 3,  2, 10,  2,  2],
       [ 1,  2,  1,  1,  2]])

但是我们可以用掩码加法做同样的事情:

In [271]: x1[x1==0] += 10
In [272]: x1
Out[272]: 
array([[ 3,  2, 10,  1,  3],
       [ 3,  2,  4, 10,  3],
       [ 2,  3,  3,  4,  3],
       [ 3,  2, 10,  2,  2],
       [ 1,  2,  1,  1,  2]])

或者使用更常用的np.where函数:

In [273]: np.where(x1==10, 20, x1)
Out[273]: 
array([[ 3,  2, 20,  1,  3],
       [ 3,  2,  4, 20,  3],
       [ 2,  3,  3,  4,  3],
       [ 3,  2, 20,  2,  2],
       [ 1,  2,  1,  1,  2]])

根据我使用 SO 的经验,where/out 在某些值的评估可能会导致错误时最有用,例如除以 0 或负数对数。

np.where(A,B,C)中,3个参数被完整计算,结果只是在A的基础上从BC中选择。对于 np.add(x, y, where=A, out=C)x+y 添加仅在条件为真时执行。评价是选择性的。区别可能难以理解,并且在使用 np.add.

时可能无关紧要