我在python中有一个带有以下元素的代码:
我有一个intensities
向量,它是这样的:
array([ 1142., 1192., 1048., ..., 29., 18., 35.])
我还有一个x
向量,如下所示:
array([ 0, 1, 1, ..., 1060, 1060, 1061])
然后,我有for循环,我填充另一个向量radialDistribution
,如下所示:
for i in range(1000):
radialDistribution[i] = sum(intensities[np.where(x == i)]) / len(np.where(x == i)[0])
问题在于它需要20秒才能完成它...因此我想对它进行矢量化。但我对Numpy的广播很新,并没有找到那么多......所以我需要你的帮助。
我尝试了这个,但没有工作:
i= np.ogrid[:1000]
intensities[i] = sum(sortedIntensities1D[np.where(sortedDists1D == i)]) / len(np.where(sortedDists1D == i)[0])
你能帮我告诉我在哪里可以学习Numpy的矢量化程序吗?
提前感谢您的宝贵帮助!
答案 0 :(得分:5)
如果您的x
向量具有从0开始的连续整数,那么您可以执行以下操作:
radialDistribution = np.bincount(x, weights=intensities) / np.bincount(x)
答案 1 :(得分:2)
Here是我在numpy中实现的group_by功能。它在概念上类似于熊猫解决方案;除了这不需要大熊猫,我认为它应该成为numpy核心的一部分。
使用此功能,您的代码将如下所示:
radialDistribution = group_by(x).mean(intensities)
并将在notime中完成。
另请参阅最后定义的test_radial函数,它可能更接近您的endgoal。
答案 2 :(得分:1)
这是一种使用广播的方法:
# arrays need to be at least 2D for broadcasting
x = np.atleast_2d(x)
# create vector of indices
i = np.atleast_2d(np.arange(x.size))
# do the vectorized calculation
bool_eq = (x == i.T)
totals = np.sum(np.where(bool_eq, intensities, 0), axis=1)
rD = totals / np.sum(bool_eq, axis=1)
这使用广播两次:在操作x == i.T
和对np.where
的调用中。不幸的是,上面的代码非常慢,甚至比原始代码慢。这里的主要瓶颈是np.where
,在这种情况下我们可以通过获取布尔数组和强度(也通过广播)的乘积来加速:
totals = np.sum(bool_eq*intensities, axis=1)
这与矩阵矢量产品基本相同,所以我们可以写:
totals = np.dot(intensities, bool_eq.T)
最终结果是比原始代码更快的代码(至少在中间数组的内存使用成为限制因素之前),但是你可能最好采用迭代方法,如其他答案之一所示
编辑:使用np.einsum
的速度更快(在我的试用版中):
totals = np.einsum('ij,j', bool_eq, intensities)
答案 3 :(得分:0)
基于https://stackoverflow.com/a/22265803/901925中的itertools.groupby
解决方案,这是一个适用于2个小数组的解决方案。
import numpy as np
import itertools
intensities = np.arange(12,dtype=float)
x=np.array([1,0,1,2,2,1,0,0,1,2,1,0]) # general, not sorted or consecutive
首先是一个bincount解决方案,根据非连续值进行调整
# using bincount
# if 'x' are not consecutive
J=np.bincount(x)>0
print np.bincount(x,weights=intensities)[J]/np.bincount(x)[J]
现在是groupby
解决方案
# using groupby;
# sort if need
I=np.argsort(x)
x=x[I]
intensities=intensities[I]
# make a record array for use by groupby
xi=np.zeros(shape=x.shape, dtype=[('intensities',float),('x',int)])
xi['intensities']=intensities
xi['x']=x
g=itertools.groupby(xi, lambda z:z['x'])
xx=np.array([np.array([z[0] for z in y[1]]).mean() for y in g])
print xx
这是一个紧凑的numpy
解决方案,使用return_index
和np.unique
的{{1}}选项。 np.split
应该排序。我对大数组的速度并不乐观,因为除了理解之外,x
和unique
还会有迭代。
split