我要添加很多矩阵。假设矩阵是[M1,M2 ...,M_n]。然后,一个简单的方法是
X = np.zeros()
for M in matrices:
X += M
在操作中,X + = M,每次执行+ =时,Python是否为X创建新内存?如果是这种情况,那似乎效率低下。有没有办法在不为X创建新内存的情况下进行就地操作?
答案 0 :(得分:1)
这可行,但在我的机器上速度不快:
numpy.sum(matrices, axis=0)
答案 1 :(得分:1)
除非你得到MemoryError,否则尝试在numpy中猜测内存使用情况是不值得的。把它交给知道编译代码的开发人员。
但是我们可以进行一些时间测试 - 这真的很重要,不是吗?
我会测试100次添加好大小的数组。
In [479]: M=np.ones((1000,1000))
您的迭代方法+ =
In [480]: %%timeit
...: X=np.zeros_like(M)
...: for _ in range(100): X+=M
...:
1 loop, best of 3: 627 ms per loop
或制作一个大小(100,1000,1000)的数组,并在第一个轴上应用np.sum
。
In [481]: timeit np.sum(np.array([M for _ in range(100)]),axis=0)
1 loop, best of 3: 1.54 s per loop
并使用np.add
ufunc。使用reduce
,我们可以按顺序将其应用于列表中的所有值。
In [482]: timeit np.add.reduce([M for _ in range(100)])
1 loop, best of 3: 1.53 s per loop
如果我使用np.sum
,range(1000)
案例会给我一个MemoryError。我没有足够的内存来容纳(1000,1000,1000)阵列。 add.reduce
也是如此,它从列表中构建一个数组。
封面下的+=
通常是隐藏的,通常是我们无关紧要的。但是对于封底下的峰值,请查看ufunc.at
:https://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.at.html#numpy.ufunc.at
对'indices'指定的元素在操作数'a'上执行无缓冲的就地操作。对于加法ufunc,此方法等效于[indices] + = b,除了为多次索引的元素累积结果。
因此X+=M
会将总和写入缓冲区,然后将该缓冲区复制到X
。有一个临时缓冲区,但最终内存使用量不会改变。
但是缓冲区的创建和复制是在快速C代码中完成的。
np.add.at
来处理缓冲操作产生一些问题(重复索引)的情况。
因此它避免了临时缓冲 - 但速度相当快。它可能是增加的索引功能,可以减慢它的速度。 (可能会有一个更公平的add.at
测试;但在这种情况下它肯定没有帮助。)
In [491]: %%timeit
...: X=np.zeros_like(M)
...: for _ in range(100): np.add.at(X,(slice(None),slice(None)),M)
1 loop, best of 3: 19.8 s per loop