我想我有一个大数据(N = 1e6 和维度 = 3)场景。我需要在我的代码中多次执行一些矩阵操作,例如 einsum、矩阵求逆等。为了给出一个想法,我想做如下的事情。
import numpy.random as rd
ndata, kdata = 1e6, 1e5
x = rd.normal(0,1,(ndata, kdata,3,3))
y = rd.normal(0,1,(ndata, kdata,3,3))
对于小的 ndata,kdata following 是一种高效便捷的方法,
xy = einsum('pqrs, pqsu -> pqru', x, y )
因为我有很大的 ndata 和 kdata 上面的方法变成了内存限制问题所以下一个赌注将是 ndata 和 kdata 上嵌套 for 循环的点积,如下所示:
xyloop1 = np.empty((ndata, kdata, 3, 3))
for j in xrange(ndata):
for k in xrange(kdata):
xyloop1[j,k] = np.dot(x[j,k], y[j,k] )
鉴于我所学的 for 循环在 python 中是令人讨厌的。此外,我想利用 numpy 的优势,因此认为 block 矩阵方法更可取,如下所示:
nstep = 200
ndiv = ndata/nstep
kstep = 200
kdiv = kdata/kstep
xyloop2 = np.empty((ndata, kdata, 3, 3))
for j in xrange(ndiv):
ji, jf = j*nstep, (j+1)*nstep
for k in xrange(kdiv):
ki, kf = k*kstep, (k+1)*kstep
xyloop2[ji:jf,ki:kf] = einsum('pqrs, pqsu -> pqru', x[ji:jf,ki:kf], y[ji:jf,ki:kf] )
此外,我还需要这些 xy 或 xyloop1 或 xyloop2 用于我的进一步计算。所以我必须在每次计算后写和读它。考虑到系统 I/O 的带宽,您认为最好的方法是方法 3,因为与方法 2 相比,它意味着更少的 I/O 和更少的迭代次数?如果您有任何其他想法或需要更多信息,请告诉我。
我是堆栈的新手,所以请对我温柔 :)。任何帮助将不胜感激。顺便说一句,我正在尝试解决大数据的混合建模问题。谢谢!
最佳答案
虽然我同意这样的评论,即唯一确定的方法是自己分析事情,但有一些指导原则可以帮助您在第一次尝试时编写高效的 numpy
代码。以下是针对您的问题的一些建议:
- 创建一个新的 numpy 数组的开销是加法/乘法成本的 1000 倍,因此方法 2 应该是低效的,因为每次调用
np.dot
都会创建一个数组,但只执行27 个加乘法。 - 如果您要在 Python 中使用较慢的 for 循环,请尽可能在最左边的轴上执行(对于 C 序数组)。
- 很难有效地编写非常通用的 N 维代码,所以我的猜测是,作为一系列更简单的
numpy
调用将比np.einsum
更有效.尝试C = np.sum(A[...,:,None] * B[...,:,:], axis=-2)
(虽然这是相当推测性的)。
所以我会尝试如下操作:
xyloop2 = np.empty((ndata, kdata, 3, 3))
for i in xrange(ndata):
xyloop2[i] = np.sum(x[i,:,:,:,None] * y[i,:,None,:,:], axis=-2)
类似于方法 2,但 for 循环更简单(也更有效)。还换掉了矩阵乘法,换成了我认为可能更快的东西。
关于Python 大数据矩阵操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26968551/