我是numpy的新手,我想计算numpy数组的所有非对角元素的绝对值之和。矩阵中的off-diagonal个元素是矩阵的所有元素,但位于主对角线上的元素除外。
我想计算它们的绝对值之和,所以我可以实现Jacobi eigenvalue algorithm的this lecture
因此,为了进行计算,我认为这段代码可以工作:
import numpy as np
off_diagonal_sum = 0
for i in range(n): # n is the dimension of our square matrix
# mat is our matrix
off_diagonal_sum = off_diagonal_sum + np.sum(np.abs(mat[i, (i + 1):n]))
off_diagonal_sum = off_diagonal_sum + np.sum(np.abs(mat[i, 0:(i - 1)]))
但是,由于我是numpy的新手,我认为应该有一种更简单,更短的方法来计算它。你有什么主意吗?
提前谢谢。
答案 0 :(得分:4)
在NumPy中有一个不错的选项,称为diag_indices,它可以返回二维数组对角线元素的索引。使用此方法,您可以获取对角线元素的总和,然后从完整数组np.sum(arr)
的总和中减去对角线元素的总和,而无需使用任何显式的for循环。要获取绝对和,只需使用np.abs
来获取每个元素的绝对值,然后执行以下任务即可。
示例
import numpy as np
arr = np.random.randint(1, 20, size=(3,3)) # Define a random 2d array
print (arr)
dia = np.diag_indices(3) # indices of diagonal elements
dia_sum = sum(arr[dia]) # sum of diagonal elements
off_dia_sum = np.sum(arr) - dia_sum # subtract the diagonal sum from total array sum
print (off_dia_sum)
[[12 19 10]
[ 3 13 18]
[16 16 6]]
82
备用1
您也可以简单地使用np.trace
来获取对角线元素的总和,然后从数组总和中减去它以获得对角线元素的总和。
off_dia_sum = np.sum(arr) - np.trace(arr)
备用2
使用np.diagonal
得到对角线元素,然后取总和并从总和中减去
dia_sum = sum(np.diagonal(arr))
off_dia_sum = np.sum(arr) - dia_sum
备用3
使用列表推导,您可以执行以下操作:仅在列表不成对角线的情况下将元素存储在列表中,这意味着两个索引i
和j
不相等。
size = len(arr)
off_dia_sum = sum([arr[i][j] for i in range(size) for j in range(size) if i!=j])
答案 1 :(得分:1)
从总和中减去迹线很快,并且在大多数情况下都很好。
但是,如果非对角线元素比对角线元素小(许多数量级),则结果可能变得不精确。
因此,这里有两种numpy解决方案,它们速度不快但更安全。
# make an example with very small off-diag elements
from scipy.spatial.distance import squareform
N = 100
A = np.identity(N) + 1e-8*np.random.random((N, N))
A = np.abs(A+A.T) # A is symmetric, also we take the absolute value right here
# method 1
np.bincount(np.identity(N, int).ravel(), A.ravel())[0]
# 9.934386601640464e-05
# method 2 - this only works with symmetric A:
2*squareform(A, checks=False).sum()
# 9.934386601640431e-05
# and the "subtract trace" method
A.sum()-A.trace()
# 9.934386602594714e-05
# with double precision all looks ok in this example
# so for the sake of demonstration let's go to single precision
A = A.astype(np.single)
np.bincount(np.identity(N, int).ravel(), A.ravel())[0]
# 9.93438660777668e-05
2*squareform(A, checks=False).sum()
# 9.93438734440133e-05
# so far so good, but ...
A.sum()-A.trace()
# 7.6293945e-05
# Ouch!