Python 使用numpy.where()遍历矩阵

Python 使用numpy.where()遍历矩阵,python,numpy,iteration,where,Python,Numpy,Iteration,Where,关于numpy.where()我不明白: 假设我有一个2D numpy Ndaray: import numpy as np twodim = np.array([[1, 2, 3, 4], [1, 6, 7, 8], [1, 1, 1, 12], [17, 3, 15, 16], [17, 3, 18, 18]]) 现在,我想创建一个函数来“检查”这个numpy数组的各种条件 array([[ 1, 2, 3, 4], [ 1, 6, 7, 8],

关于
numpy.where()
我不明白:

假设我有一个2D numpy Ndaray:

import numpy as np
twodim =  np.array([[1, 2, 3, 4],  [1, 6, 7, 8], [1, 1, 1, 12],  [17, 3, 15, 16], [17, 3, 18, 18]])
现在,我想创建一个函数来“检查”这个numpy数组的各种条件

array([[ 1,  2,  3,  4],
       [ 1,  6,  7,  8],
       [ 1,  1,  1, 12],
       [17,  3, 15, 16],
       [17,  3, 18, 18]])
例如,此数组中哪些条目的(A)偶数(B)大于7(C)可被3整除

我想为此使用
numpy.where()
,并遍历此数组的每个条目,最后找到匹配所有条件的元素(如果存在这样的条目):

如何做到这一点?我不知道如何迭代布尔值

我可以通过以下方式访问矩阵(I,j)的索引:

我们可以这样做

import numpy as np
twodim =  np.array([[1, 2, 3, 4],  [1, 6, 7, 8], [1, 1, 1, 12],  [17, 3, 15, 16], [17, 3, 18, 18]])
even_entries = np.where(twodim % 2 == 0)
greater_seven = np.where(twodim > 7 )
divisible_three = np.where(twodim % 3 == 0)
for row in even_entries:
    for item in row:
        if item: #equivalent to `if item == True`
                for row in greater_seven:
                    for item in row:
                        if item: #equivalent to `if item == True`
                            for row in divisible_three:
                                for item in row:
                                    if item: #equivalent to `if item == True`
                                        # something like print(np.argwhere())
有什么建议吗

编辑1:下面是好主意。正如@hpaulj提到的,“您的测试生成一个与twodim形状相同的布尔矩阵” 这是我在玩弄时遇到的一个问题——并非所有条件产生的矩阵都与我的起始矩阵的形状相同。例如,假设我在比较数组元素的左侧或右侧(即水平方向)是否有匹配的数组

这将产生一个(5,3)布尔数组,而我们的原始矩阵是一个(5,4)数组

如果我们在垂直方向上做同样的操作,则会得到一个(4,4)布尔数组,而原始矩阵是(5,4)


如果我们想知道哪些条目同时具有垂直和水平对,那么找出我们所处的维度是非常重要的

如果要找到满足这三个条件的位置:

import numpy as np
twodim =  np.array([[1, 2, 3, 4],  [1, 6, 7, 8], [1, 1, 1, 12],  [17, 3, 15, 16], [17, 3, 18, 18]])

mask = (twodim % 2 == 0) & (twodim > 7) & (twodim % 3 =0)

print(twodim[mask])

[12 18 18]

不确定您到底想要什么,行中的所有元素是否必须满足条件并找到这些行,或者您是否想要单个元素。

您的测试生成一个与
twodim
形状相同的布尔矩阵:

import numpy as np
twodim =  np.array([[1, 2, 3, 4],  [1, 6, 7, 8], [1, 1, 1, 12],  [17, 3, 15, 16], [17, 3, 18, 18]])
condition = (twodim % 2. == 0.) & (twodim > 7.) & (twodim % 3. ==0.)
location = np.argwhere(condition == True) 


for i in location: 
     print i, twodim[i[0],i[1]],

>>> [2 3] 12 [4 2] 18 [4 3] 18
In [487]: mask3 = twodim%3==0
In [488]: mask3
Out[488]: 
array([[False, False,  True, False],
       [False,  True, False, False],
       [False, False, False,  True],
       [False,  True,  True, False],
       [False,  True,  True,  True]], dtype=bool)
正如其他答案所指出的那样,你可以逻辑地将测试与and和or结合起来

np.where
np.nonzero
(在本用法中)相同,只返回真值的坐标-作为两个数组的元组

In [489]: np.nonzero(mask3)
Out[489]: 
(array([0, 1, 2, 3, 3, 4, 4, 4], dtype=int32),
 array([2, 1, 3, 1, 2, 1, 2, 3], dtype=int32))
argwhere
返回相同的值,但作为转置的二维数组

In [490]: np.argwhere(mask3)
Out[490]: 
array([[0, 2],
       [1, 1],
       [2, 3],
       [3, 1],
       [3, 2],
       [4, 1],
       [4, 2],
       [4, 3]], dtype=int32)
掩码
元组
都可用于直接为数组编制索引:

In [494]: twodim[mask3]
Out[494]: array([ 3,  6, 12,  3, 15,  3, 18, 18])
In [495]: twodim[np.nonzero(mask3)]
Out[495]: array([ 3,  6, 12,  3, 15,  3, 18, 18])
argwhere
不能直接用于索引,但可能更适合于迭代,尤其是如果您需要索引和值:

In [496]: for i,j in np.argwhere(mask3):
   .....:     print(i,j,twodim[i,j])
   .....:     
0 2 3
1 1 6
2 3 12
3 1 3
3 2 15
4 1 3
4 2 18
4 3 18
相同,其中
需要
邮政编码:

for i,j in zip(*np.nonzero(mask3)): print(i,j,twodim[i,j])
但通常在
numpy
中,我们试图避免迭代。如果您可以直接使用
twodim[mask]
,您的代码将更快

布尔掩码的逻辑组合比
where
索引的组合更容易生成。要使用索引,我可能会求助于
set
操作(并集、相交、差分)


对于缩减大小的测试,您必须决定如何映射到原始阵列(以及其他测试)。e、 g

(5,3)掩码(列之间的差异):

它可以索引原始数组的3列

In [507]: twodim[:,:-1][dmask]
Out[507]: array([ 1,  2,  3,  1,  6,  7,  1, 17,  3, 15, 17,  3])
In [508]: twodim[:,1:][dmask]
Out[508]: array([ 2,  3,  4,  6,  7,  8, 12,  3, 15, 16,  3, 18])
它还可以与另一个掩码的3列组合:

In [509]: dmask & mask3[:,:-1]
Out[509]: 
array([[False, False,  True],
       [False,  True, False],
       [False, False, False],
       [False,  True,  True],
       [False,  True, False]], dtype=bool)

以布尔数组形式组合测试比使用
where
索引更容易。

不要使用
where
。我不知道为什么新的NumPy用户一直在使用它,但这很少是个好主意。通过直接使用布尔掩码,您可以更轻松地完成此任务。@hpaulj“您的测试生成的布尔矩阵的形状与twodim相同”这是我在玩弄时遇到的一个问题——并非所有条件生成的矩阵的形状都与我的起始矩阵相同。请参见上面的评论,我添加了您的示例。谢谢。上面有件事我还没明白。我们的原始矩阵是(5,4),
dmask
是(5,3)。我们的组合最终面具不是应该成形(5,4)吗?行与行之间的差异如何,即形状(4,4)。因此,要知道哪些条目具有水平合作伙伴和垂直合作伙伴。什么是“最终面具”?现在我想起来了,你的方法是正确的。最终矩阵“遮罩”应成形(4,3)。我仍然有点困惑,在这个设置中,对是在哪里被认为的。
argwhere
对来自缩小尺寸的掩码。将它们映射到原始数组可能需要使用索引调整,如
twodim[i,j+1]
。我很乐意这样做。不幸的是,正如我在上面编辑的那样,在某些条件下很难创建这样的掩码。尺寸没有正确地在一起传播。@ShanZhengYang:然后只需将重叠部分切掉到一起,或者在创建遮罩的过程中进行切分(因此
twodim[适当:片段]>7
)。试图处理
,其中的
输出会慢得多,也会更麻烦。
In [494]: twodim[mask3]
Out[494]: array([ 3,  6, 12,  3, 15,  3, 18, 18])
In [495]: twodim[np.nonzero(mask3)]
Out[495]: array([ 3,  6, 12,  3, 15,  3, 18, 18])
In [496]: for i,j in np.argwhere(mask3):
   .....:     print(i,j,twodim[i,j])
   .....:     
0 2 3
1 1 6
2 3 12
3 1 3
3 2 15
4 1 3
4 2 18
4 3 18
for i,j in zip(*np.nonzero(mask3)): print(i,j,twodim[i,j])
In [505]: dmask=np.diff(twodim, 1).astype(bool)
In [506]: dmask
Out[506]: 
array([[ True,  True,  True],
       [ True,  True,  True],
       [False, False,  True],
       [ True,  True,  True],
       [ True,  True, False]], dtype=bool)
In [507]: twodim[:,:-1][dmask]
Out[507]: array([ 1,  2,  3,  1,  6,  7,  1, 17,  3, 15, 17,  3])
In [508]: twodim[:,1:][dmask]
Out[508]: array([ 2,  3,  4,  6,  7,  8, 12,  3, 15, 16,  3, 18])
In [509]: dmask & mask3[:,:-1]
Out[509]: 
array([[False, False,  True],
       [False,  True, False],
       [False, False, False],
       [False,  True,  True],
       [False,  True, False]], dtype=bool)