Python 如何在numpy中矢量化此循环差异?

Python 如何在numpy中矢量化此循环差异?,python,matlab,numpy,linear-algebra,Python,Matlab,Numpy,Linear Algebra,我觉得应该有一个快速的方法来加速这个代码。我想答案是肯定的,但我似乎无法以那种方式解决我的问题。我试图解决的基本问题是找到平行和垂直分量的逐点差异,并创建这些差异的二维直方图 out = np.zeros((len(rpbins)-1,len(pibins)-1)) tmp = np.zeros((len(x),2)) for i in xrange(len(x)): tmp[:,0] = x - x[i] tmp[:,1] = y - y[i] para = np.s

我觉得应该有一个快速的方法来加速这个代码。我想答案是肯定的,但我似乎无法以那种方式解决我的问题。我试图解决的基本问题是找到平行和垂直分量的逐点差异,并创建这些差异的二维直方图

out = np.zeros((len(rpbins)-1,len(pibins)-1))
tmp = np.zeros((len(x),2))
for i in xrange(len(x)):
    tmp[:,0] = x - x[i]
    tmp[:,1] = y - y[i]

    para = np.sum(tmp**2,axis=-1)**(1./2)
    perp = np.abs(z - z[i])

    H, _, _ = np.histogram2d(para, perp, bins=[rpbins, pibins])
    out += H

像这样的矢量化是很棘手的,因为要摆脱
n
元素上的循环,您必须构造一个
(n,n)
数组,因此对于大型输入,您可能会获得比Python循环更差的性能。但这是可以做到的:

mask = np.triu_indices(x.shape[0], 1)
para = np.sqrt((x[:, None] - x)**2 + (y[:, None] - y)**2)
perp = np.abs(z[:, None] - z)
hist, _, _ = np.histogram2d(para[mask], perp[mask], bins=[rpbins, pibins])
遮罩
是为了避免将每个距离计算两次。我还将对角线偏移设置为
1
,以避免在直方图中包含每个点到自身的
0
距离。但是,如果不使用它为
para
perp
编制索引,则会得到与代码完全相同的结果

使用此示例数据:

items = 100
rpbins, pibins = np.linspace(0, 1, 3), np.linspace(0, 1, 3)
x = np.random.rand(items)
y = np.random.rand(items)
z = np.random.rand(items)
我为我的
hist
和你的
out
得到这个:

>>> hist
array([[ 1795.,   651.],
       [ 1632.,   740.]])
>>> out
array([[ 3690.,  1302.],
       [ 3264.,  1480.]])
out[i,j]=2*hist[i,j]
,除了
i=j=0
,其中
out[0,0]=2*hist[0,0]+项
,因为每个项与自身的距离
0


编辑在tcaswell的评论后尝试了以下操作:

items = 1000
rpbins, pibins = np.linspace(0, 1, 3), np.linspace(0, 1, 3)
x, y, z = np.random.rand(3, items)

def hist1(x, y, z, rpbins, pibins) :
    mask = np.triu_indices(x.shape[0], 1)
    para = np.sqrt((x[:, None] - x)**2 + (y[:, None] - y)**2)
    perp = np.abs(z[:, None] - z)
    hist, _, _ = np.histogram2d(para[mask], perp[mask], bins=[rpbins, pibins])
    return hist

def hist2(x, y, z, rpbins, pibins) :
    mask = np.triu_indices(x.shape[0], 1)
    para = np.sqrt((x[:, None] - x)[mask]**2 + (y[:, None] - y)[mask]**2)
    perp = np.abs((z[:, None] - z)[mask])
    hist, _, _ = np.histogram2d(para, perp, bins=[rpbins, pibins])
    return hist

def hist3(x, y, z, rpbins, pibins) :
    mask = np.triu_indices(x.shape[0], 1)
    para = np.sqrt(((x[:, None] - x)**2 + (y[:, None] - y)**2)[mask])
    perp = np.abs((z[:, None] - z)[mask])
    hist, _, _ = np.histogram2d(para, perp, bins=[rpbins, pibins])
    return hist

In [10]: %timeit -n1 -r10 hist1(x, y, z, rpbins, pibins)
1 loops, best of 10: 289 ms per loop

In [11]: %timeit -n1 -r10 hist2(x, y, z, rpbins, pibins)
1 loops, best of 10: 294 ms per loop

In [12]: %timeit -n1 -r10 hist3(x, y, z, rpbins, pibins)
1 loops, best of 10: 278 ms per loop

似乎大部分时间都花在实例化新数组上,而不是进行实际计算,因此虽然可以节省一些效率,但实际上效率并不高。

我之所以给它加上标签,主要是因为E先生的评论:“我用matlab对此进行了标记,因为matlab用户可能知道一个简单的解决方案,通常情况下,Numpy中没有相应的函数“对不起,我不该这么做。标签上写得很公平。先生,您是位绅士和学者。关于内存使用情况,您是正确的,但是您的屏蔽非常有用。来自另一个圣迪亚古安的谢谢你。。。Diagan。。。迪戈伊斯特…:DYou仍在
sqrt
步骤上进行双重计算。我怀疑,如果在求平方根之前进行掩蔽,您可以在内存和运行时方面做得更好。@tcaswell刚刚尝试过它,确实有一些,但不多,请参见我的编辑。另一个微选项:您可以使用
hypot
而不是
sqrt(a**2+b**2)
它在这里可能不会有多大效果,因为这并不是大部分时间都花在的地方。显然,这是另一个提醒,ram实际上很慢。很抱歉让你白费力气。