numpy中用最少的内存求和上三角元素的最快方法

时间:2019-02-11 11:28:57

标签: python arrays performance numpy

我需要对对称矩阵执行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中使用的方式。

4 个答案:

答案 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()绝对拆除。