如何计算一个numpy数组的所有非对角元素的绝对和?

时间:2018-12-20 00:14:16

标签: python numpy matrix

我是numpy的新手,我想计算numpy数组的所有非对角元素的绝对值之和。矩阵中的off-diagonal个元素是矩阵的所有元素,但位于主对角线上的元素除外。

我想计算它们的绝对值之和,所以我可以实现Jacobi eigenvalue algorithmthis 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的新手,我认为应该有一种更简单,更短的方法来计算它。你有什么主意吗?

提前谢谢。

2 个答案:

答案 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

使用列表推导,您可以执行以下操作:仅在列表不成对角线的情况下将元素存储在列表中,这意味着两个索引ij不相等。

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!