How to get indices of non-diagonal elements of a numpy array?
a = np.array([[7412, 33, 2],
[2, 7304, 83],
[3, 101, 7237]])
I tried as follows:
diag_indices = np.diag_indices_from(a)
print diag_indices
(array([0, 1, 2], dtype=int64), array([0, 1, 2], dtype=int64))
After that, no idea... The expected result should be:
result = [[False, True, True],
[True, False, True],
[True, True, False]]
To get the mask, you can use np.eye
, like so -
~np.eye(a.shape[0],dtype=bool)
To get the indices, add np.where
-
np.where(~np.eye(a.shape[0],dtype=bool))
Sample run -
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]))
There are few more ways to get such a mask for a generic non-square input array.
With np.fill_diagonal
-
out = np.ones(a.shape,dtype=bool)
np.fill_diagonal(out,0)
With broadcasting
-
m,n = a.shape
out = np.arange(m)[:,None] != np.arange(n)
>>> 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)
As an additional idea to previous answers, you could select the indices of the upper and lower triangles :
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))
As described in the doc , you can then use those to index and assign values:
out = np.ones((3,3), dtype=bool)
out[(x, y)] = False
gives:
>>> out
array([[ True, False, False],
[False, True, False],
[False, False, True]])
To extend @PlasmaBinturong's and @Divakar's answers, you could use advanced indexing based on np.triu_indices
and np.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)
is a shorthand for np.nonzero(np.less.outer(np.arange(len(a)), np.arange(len(a))))
np.tril_indices(len(a), k=-1)
is a shorthand for np.nonzero(np.greater.outer(np.arange(len(a)), np.arange(len(a))))
So instead of np.less.outer(...)
& np.greater.outer(...)
you could use:
>>> np.not_equal.outer(np.arange(len(a)), np.arange(len(a)))
array([[False, True, True],
[ True, False, True],
[ True, True, False]])
which could be replaced by Syntactic Sugar in @Divakar's solution: np.arange(len(a))[:, None] != np.arange(len(a))
This is an output desired but besides that, let's plug it into a previous code to compare with the previous process:
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]])
Conclusion . Don't convert boolean indices to numerical ones and then back. This is inefficient as to compare with working on boolean indices straight.
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))
gives
array([[False, True, True],
[ True, False, True],
[ True, True, False]])
When a Boolean diagonal matrix is inverted, off-diagonal terms become True while the diagonal terms are False.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.