我需要对对称矩阵执行i<j
类的求和。这等于对矩阵的上三角元素求和,不包括对角线。
考虑到A
是对称的N x N
数组,最简单的解决方案是np.triu(A,1).sum()
,但是我想知道是否存在需要较少内存的更快方法。
看来(A.sum() - np.diag(A).sum())/2
在大型数组上速度更快,但是如何避免从N x 1
创建np.diag
数组呢?
双重嵌套的for循环不需要额外的内存,但是显然这不是在Python中使用的方式。
答案 0 :(得分:2)
将我的2美分添加到其他答案和评论中的想法中,您可能会对1000x1000对称矩阵的以下时间性能感兴趣。如您所见,在这种情况下,sum_diag
方法获胜了。
import numpy as np
N = 1000
a = np.random.randint(-2000,2000,size=(N,N))
A = (a + a.T)/2
def sum_triu(A):
return np.triu(A,1).sum()
def sum_diag(A):
return (A.sum() - np.diag(A).sum())/2
def sum_trace(A):
return (A.sum() - np.trace(A))/2
%timeit sum_triu(A)
# 3.65 ms ± 406 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit sum_diag(A)
# 663 µs ± 88.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit sum_trace(A)
# 732 µs ± 120 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
答案 1 :(得分:1)
您可以将np.diag(A).sum()
替换为np.trace(A)
;这不会创建临时Nx1
数组
答案 2 :(得分:0)
您可以使用Einstein notation对角线求和:np.einsum('ii', a)
等效于np.diag(a).sum()
。为了进行基准测试:
import numpy as np
a = np.arange(25).reshape(5, 5)
%timeit np.einsum('ii', a)
1.72 µs ± 88.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit np.diag(a).sum()
3.93 µs ± 29.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
答案 3 :(得分:0)
用最少的内存,最快的内存最少的方法是将整个东西相加并减去对角线。
就FLOPS而言,这可能会很浪费,但是请注意,相对于该实现,理论上的节省只是一个因素2。如果这对您来说意味着什么,那么您一开始就不应该使用numpy。
此外,numpy从根本上处理可作为跨步视图寻址的内存块。如果您可以在三角形上看到一个跨步视图,则可能会导致高效的numpy实现。但是您不能(证明是练习的余地),因此您可以放心地忘记任何真正的numpy解决方案,而这些解决方案都不是为您解决问题的优化C例程的调用。而且我不知道。
但实际上,即使是“优化的” C循环也可能会被A.sum()踢破。如果A是连续的,则该总和可能会调度最大程度地优化了缓存并优化了SIMD的代码路径。可能,您自己编写的任何vanilly-C都会在基准测试中被A.sum()绝对拆除。