python - 使用 numpy.where() 遍历矩阵

标签 python numpy iteration where-clause

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

假设我有一个 2D numpy ndarray:

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(),并遍历该数组的每个条目,最终找到匹配所有条件的元素(如果存在这样的条目):

   even_entries = np.where(twodim % 2 == 0)
   greater_seven = np.where(twodim > 7 )
   divisible_three = np.where(twodim % 3 == 0)

如何做到这一点?我不确定如何遍历 bool 值...

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

np.argwhere(even_entries)

我们可以做类似的事情

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())

有什么建议吗?

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

twodim[:, :-1] == twodim[:, 1:]

结果是 (5,3) bool 数组,而我们的原始矩阵是 (5,4) 数组

array([[False, False, False],
       [False, False, False],
       [ True,  True, False],
       [False, False, False],
       [False, False,  True]], dtype=bool)

如果我们在垂直方向上做同样的事情,就会得到一个 (4,4) bool 数组,而原始矩阵是 (5,4)

twodim[:-1] == twodim[1:]

array([[ True, False, False, False],
       [ True, False, False, False],
       [False, False, False, False],
       [ True,  True, False, False]], dtype=bool) 

如果我们想知道哪些条目同时有垂直和水平对,那么弄清楚我们在哪个维度是很重要的。

最佳答案

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

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)

正如其他答案所指出的那样,您可以在逻辑上结合测试 - 与和或。

np.wherenp.nonzero(在此使用中)相同,并且仅返回 True 值的坐标 - 作为 2 个数组的元组。

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)

masktuple 都可以用来直接索引你的数组:

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

where 需要一个zip:

for i,j in zip(*np.nonzero(mask3)): print(i,j,twodim[i,j])

但一般来说,在 numpy 中,我们尽量避免迭代。如果您可以直接使用 twodim[mask],您的代码会快得多。

bool 掩码的逻辑组合比 where 索引的组合更容易产生。要使用索引,我可能会求助于 set 操作(联合、交叉、差异)。


至于缩减大小的测试,您必须决定它如何映射到原始数组(以及其他测试)。例如

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

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)

可以索引原数组的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)

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

关于python - 使用 numpy.where() 遍历矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34229074/

相关文章:

python - 从多个较小的二维数组形成一个大的二维数组

python - 如何使用python比较大圆距离和两个球面点的欧氏距离?

c++ - 递归 -> 迭代

javascript - 如何在 JavaScript 中将自下而上的递归算法转换为迭代堆栈

python - 获取数据框中不同 ID 的行值

python - keras 预测错误

python - 如何在 python 中生成 RGB 立方体矩阵?

python - 如何停止遍历当前根并迭代到下一个根

python - 矩阵乘法和数组点的区别

python - n 二叉树的后序遍历