使用 numpy.where() 遍历矩阵
Using numpy.where() to iterate through a matrix
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]])
现在,想创建一个函数,其中 "checks" 这个 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)
如何做到这一点?我不确定如何遍历布尔值...
我可以通过
访问矩阵 (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 提到的 "Your tests produce a boolean matrix of the same shape as twodim"
这是我在玩弄时 运行 遇到的一个问题 --- 并非所有条件生成的矩阵都与我的起始矩阵形状相同。例如,假设我正在比较数组元素是否在左侧或右侧(即水平方向)具有匹配的数组
twodim[:, :-1] == twodim[:, 1:]
结果是 (5,3) 布尔数组,而我们的原始矩阵是 (5,4) 数组
array([[False, False, False],
[False, False, False],
[ True, True, False],
[False, False, False],
[False, False, True]], dtype=bool)
如果我们在垂直方向上做同样的事情,就会得到一个 (4,4) 布尔数组,而原始矩阵是 (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)
如果我们想知道哪些条目同时具有 垂直和水平对,那么弄清楚我们处于哪个维度并不容易。
如果要查找满足所有三个条件的位置:
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]
不确定你到底想要什么,是行中的所有元素都必须满足条件并找到这些行,还是你想要单个元素。
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
您的测试生成了一个与 twodim
:
形状相同的布尔矩阵
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
相同(在此使用中),只是 returns 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
returns 相同的值,但作为转置二维数组。
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)
mask
和 tuple
都可用于直接索引您的数组:
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]
你的代码会更快。
布尔掩码的逻辑组合比 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)
以布尔数组形式组合测试仍然比使用 where
索引更容易。
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]])
现在,想创建一个函数,其中 "checks" 这个 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)
如何做到这一点?我不确定如何遍历布尔值...
我可以通过
访问矩阵 (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 提到的 "Your tests produce a boolean matrix of the same shape as twodim" 这是我在玩弄时 运行 遇到的一个问题 --- 并非所有条件生成的矩阵都与我的起始矩阵形状相同。例如,假设我正在比较数组元素是否在左侧或右侧(即水平方向)具有匹配的数组
twodim[:, :-1] == twodim[:, 1:]
结果是 (5,3) 布尔数组,而我们的原始矩阵是 (5,4) 数组
array([[False, False, False],
[False, False, False],
[ True, True, False],
[False, False, False],
[False, False, True]], dtype=bool)
如果我们在垂直方向上做同样的事情,就会得到一个 (4,4) 布尔数组,而原始矩阵是 (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)
如果我们想知道哪些条目同时具有 垂直和水平对,那么弄清楚我们处于哪个维度并不容易。
如果要查找满足所有三个条件的位置:
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]
不确定你到底想要什么,是行中的所有元素都必须满足条件并找到这些行,还是你想要单个元素。
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
您的测试生成了一个与 twodim
:
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
相同(在此使用中),只是 returns 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
returns 相同的值,但作为转置二维数组。
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)
mask
和 tuple
都可用于直接索引您的数组:
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]
你的代码会更快。
布尔掩码的逻辑组合比 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)
以布尔数组形式组合测试仍然比使用 where
索引更容易。