如何获取NumPy数组非对角线元素的索引?

18

如何获取numpy数组的非对角线元素的索引?

a = np.array([[7412, 33, 2],
              [2, 7304, 83],
              [3, 101, 7237]])

我尝试了以下方法:

diag_indices = np.diag_indices_from(a)
print diag_indices
(array([0, 1, 2], dtype=int64), array([0, 1, 2], dtype=int64))

之后,没有任何想法...

result = [[False, True, True],
        [True, False, True],
         [True, True, False]]
5个回答

27

要获取掩码,您可以使用np.eye函数进行操作,如下所示 -

~np.eye(a.shape[0],dtype=bool)

为了获取索引,需要添加 np.where函数 -

np.where(~np.eye(a.shape[0],dtype=bool))

示例运行 -

In [142]: a
Out[142]: 
array([[7412,   33,    2],
       [   2, 7304,   83],
       [   3,  101, 7237]])

In [143]: ~np.eye(a.shape[0],dtype=bool)
Out[143]: 
array([[False,  True,  True],
       [ True, False,  True],
       [ True,  True, False]], dtype=bool)

In [144]: np.where(~np.eye(a.shape[0],dtype=bool))
Out[144]: (array([0, 0, 1, 1, 2, 2]), array([1, 2, 0, 2, 0, 1]))

有几种方法可以为一个一般的非正方形输入数组获得这样的掩码。

使用np.fill_diagonal函数 -

out = np.ones(a.shape,dtype=bool)
np.fill_diagonal(out,0)

使用broadcasting -

m,n = a.shape
out = np.arange(m)[:,None] != np.arange(n)

为什么要使用a.shape [0]而不是a? - gudlife
@gudlife 因为 np.eye() 接受形状参数来创建这样的二维数组。 - Divakar

2
>>> import numpy as np
>>> a = np.array([[7412, 33, 2],
...               [2, 7304, 83],
...               [3, 101, 7237]])
>>> non_diag = np.ones(shape=a.shape, dtype=bool) - np.identity(len(a)).astype(bool)
>>> non_diag
array([[False,  True,  True],
       [ True, False,  True],
       [ True,  True, False]], dtype=bool)

在当前版本的numpy中,我得到了TypeError: numpy boolean subtract, the '-' operator, is not supported, use the bitwise_xor, the '^' operator, or the logical_xor function instead.错误提示。请使用位异或运算符'^'或逻辑异或函数logical_xor代替减法运算符'-'。 - Aaron Bramson
这段代码是可行的:nonDiag = (np.ones(shape=a.shape) - np.identity(len(a))).astype(bool) - Aaron Bramson

0
import numpy as np
a = np.array([[7412, 33, 2],
              [2, 7304, 83],
              [3, 101, 7237]])
np.invert(np.eye(a.shape[0], dtype=bool))

提供

array([[False,  True,  True],
       [ True, False,  True],
       [ True,  True, False]])

当布尔对角矩阵被反转时,非对角线术语变为True,而对角线术语为False。

0

为了扩展@PlasmaBinturong和@Divakar的答案,您可以使用基于np.triu_indicesnp.tril_indices的高级索引:

triu_idx = np.triu_indices(len(a), k=1) #finding advanced indices of upper right triangle
tril_idx = np.tril_indices(len(a), k=-1) #finding advanced indices of lower left triangle
out = np.ones(a.shape, dtype=bool)
out[triu_idx] = False #padding upper right triangle with zeros
out[tril_idx] = False #padding upper left triangle with zeros
>>> out
array([[ True, False, False],
       [False,  True, False],
       [False, False,  True]])
  • 对于triu_idx = np.triu_indices(len(a), k=1),它是np.nonzero(np.less.outer(np.arange(len(a)), np.arange(len(a))))的缩写。

  • 对于np.tril_indices(len(a), k=-1),它是np.nonzero(np.greater.outer(np.arange(len(a)), np.arange(len(a))))的缩写。

所以你可以使用np.less.outer(...)np.greater.outer(...)的替代方式:

>>> np.not_equal.outer(np.arange(len(a)), np.arange(len(a)))
array([[False,  True,  True],
       [ True, False,  True],
       [ True,  True, False]])

在 @Divakar 的解决方案中,可以用语法糖来替换:np.arange(len(a))[:, None] != np.arange(len(a))

除此之外,我们还希望得到以下输出结果,并将其与先前的过程进行比较:

out = np.ones(a.shape, dtype=bool)
idx = np.not_equal.outer(np.arange(len(a)), np.arange(len(a))) # you need only this
tri_both = np.nonzero(idx)
out[tri_both] = False
>>> out
array([[False,  True,  True],
       [ True, False,  True],
       [ True,  True, False]])

结论。不要将布尔索引转换为数字索引,然后再转回来。这样做效率低下,与直接使用布尔索引相比。


0
作为之前回答的补充,你可以选择 上三角下三角 的索引:
a = np.array([[7412, 33, 2],
              [2, 7304, 83],
              [3, 101, 7237]])
# upper triangle. k=1 excludes the diagonal elements.
xu, yu = np.triu_indices_from(a, k=1)
# lower triangle
xl, yl = np.tril_indices_from(a, k=-1)  # Careful, here the offset is -1

# combine
x = np.concatenate((xl, xu))
y = np.concatenate((yl, yu))

文档所述,您可以使用它们来索引和赋值:
out = np.ones((3,3), dtype=bool)
out[(x, y)] = False

给出:

>>> out
array([[ True, False, False],
   [False,  True, False],
   [False, False,  True]])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接