如何解决有效地在python中生成点的晶格
| 帮助提高我的代码速度:我的python代码需要生成一个落在边界矩形内的二维点阵。我将产生该晶格的一些代码(如下所示)合并在一起。但是,此函数被多次调用,并且已成为我的应用程序中的严重瓶颈。 我敢肯定有一种更快的方法,可能涉及numpy数组而不是列表。对于更快,更优雅的方式有什么建议吗? 功能说明: 我有两个2D向量,v1和v2。这些向量定义了一个晶格。在我的情况下,我的向量定义了几乎但不完全是六边形的格子。我想在此边界上的某个边界矩形中生成所有2D点的集合。在我的情况下,矩形的一个角位于(0,0),其他角位于正坐标。 例: 如果边界矩形的最远角为(3,3),并且我的晶格矢量为:v1 = (1.2,0.1)
v2 = (0.2,1.1)
我希望我的函数返回点:
(1.2,0.1) #v1
(2.4,0.2) #2*v1
(0.2,1.1) #v2
(0.4,2.2) #2*v2
(1.4,1.2) #v1 + v2
(2.6,1.3) #2*v1 + v2
(1.6,2.3) #v1 + 2*v2
(2.8,2.4) #2*v1 + 2*v2
我不在乎极端情况;例如,函数是否返回(0,0)都无关紧要。
我目前正在执行的速度很慢:
import numpy,pylab
def generate_lattice( #Help me speed up this function,please!
image_shape,lattice_vectors,center_pix=\'image\',edge_buffer=2):
##Preprocessing. Not much of a bottleneck:
if center_pix == \'image\':
center_pix = numpy.array(image_shape) // 2
else: ##Express the center pixel in terms of the lattice vectors
center_pix = numpy.array(center_pix) - (numpy.array(image_shape) // 2)
lattice_components = numpy.linalg.solve(
numpy.vstack(lattice_vectors[:2]).T,center_pix)
lattice_components -= lattice_components // 1
center_pix = (lattice_vectors[0] * lattice_components[0] +
lattice_vectors[1] * lattice_components[1] +
numpy.array(image_shape)//2)
num_vectors = int( ##Estimate how many lattice points we need
max(image_shape) / numpy.sqrt(lattice_vectors[0]**2).sum())
lattice_points = []
lower_bounds = numpy.array((edge_buffer,edge_buffer))
upper_bounds = numpy.array(image_shape) - edge_buffer
##SLOW LOOP HERE. \'num_vectors\' is often quite large.
for i in range(-num_vectors,num_vectors):
for j in range(-num_vectors,num_vectors):
lp = i * lattice_vectors[0] + j * lattice_vectors[1] + center_pix
if all(lower_bounds < lp) and all(lp < upper_bounds):
lattice_points.append(lp)
return lattice_points
##Test the function and display the output.
##No optimization needed past this point.
lattice_vectors = [
numpy.array([-40.,-1.]),numpy.array([ 18.,-37.])]
image_shape = (1000,1000)
spots = generate_lattice(image_shape,lattice_vectors)
fig=pylab.figure()
pylab.plot([p[1] for p in spots],[p[0] for p in spots],\'.\')
pylab.axis(\'equal\')
fig.show()
解决方法
如果要对整个对象进行矢量化处理,请生成一个方格,然后对其进行剪切。然后切掉落在盒子外面的边缘。
这是我想出的。仍然可以进行很多改进,但这是基本思想。
def generate_lattice(image_shape,lattice_vectors) :
center_pix = numpy.array(image_shape) // 2
# Get the lower limit on the cell size.
dx_cell = max(abs(lattice_vectors[0][0]),abs(lattice_vectors[1][0]))
dy_cell = max(abs(lattice_vectors[0][1]),abs(lattice_vectors[1][1]))
# Get an over estimate of how many cells across and up.
nx = image_shape[0]//dx_cell
ny = image_shape[1]//dy_cell
# Generate a square lattice,with too many points.
# Here I generate a factor of 4 more points than I need,which ensures
# coverage for highly sheared lattices. If your lattice is not highly
# sheared,than you can generate fewer points.
x_sq = np.arange(-nx,nx,dtype=float)
y_sq = np.arange(-ny,dtype=float)
x_sq.shape = x_sq.shape + (1,)
y_sq.shape = (1,) + y_sq.shape
# Now shear the whole thing using the lattice vectors
x_lattice = lattice_vectors[0][0]*x_sq + lattice_vectors[1][0]*y_sq
y_lattice = lattice_vectors[0][1]*x_sq + lattice_vectors[1][1]*y_sq
# Trim to fit in box.
mask = ((x_lattice < image_shape[0]/2.0)
& (x_lattice > -image_shape[0]/2.0))
mask = mask & ((y_lattice < image_shape[1]/2.0)
& (y_lattice > -image_shape[1]/2.0))
x_lattice = x_lattice[mask]
y_lattice = y_lattice[mask]
# Translate to the centre pix.
x_lattice += center_pix[0]
y_lattice += center_pix[1]
# Make output compatible with original version.
out = np.empty((len(x_lattice),2),dtype=float)
out[:,0] = y_lattice
out[:,1] = x_lattice
return out
,由于lower_bounds
和upper_bounds
只是2个元素的数组,因此numpy在这里可能不是正确的选择。尝试更换
if all(lower_bounds < lp) and all(lp < upper_bounds):
基本的Python内容:
if lower1 < lp and lower2 < lp and lp < upper1 and lp < upper2:
根据timeit,第二种方法要快得多:
>>> timeit.timeit(\'all(lower < lp)\',\'import numpy\\nlp=4\\nlower = numpy.array((1,5))\')
3.7948939800262451
>>> timeit.timeit(\'lower1 < 4 and lower2 < 4\',\'lp = 4\\nlower1,lower2 = 1,5\')
0.074192047119140625
根据我的经验,只要您不需要处理n维数据,并且如果不需要双精度浮点数,通常使用基本的Python数据类型和构造而不是numpy会更快,这是一种在这种情况下有点过载-请看另一个问题。
另一个小的改进可能是只计算一次“ 9”,然后重新使用它。另外,您可能希望使用乘积迭代器,而不是嵌套的for循环-尽管我认为这些更改不会对性能产生重大影响。
,可能您可以用此替换两个for循环。
i,j = numpy.mgrid[-num_vectors:num_vectors,-num_vectors:num_vectors]
numel = num_vectors ** 2;
i = i.reshape(numel,1)
j = j.reshape(numel,1)
lp = i * lattice_vectors[0] + j * lattice_vectors[1] + center_pix
valid = numpy.all(lower_bounds < lp,1) and numpy.all(lp < upper_bounds,1)
lattice_points = lp[valid]
可能会有一些小错误,但是您明白了。
编辑
我对\“ numpy.all(lower_bounds ..)\”进行了修改,以说明正确的尺寸。
,通过用重复的加法而不是乘法替换your11 computation的计算,我得到了超过2倍的提速。 xrange
优化似乎无关紧要(尽管可能不会造成伤害)。重复加法似乎比乘法更有效。将此与上面提到的其他优化结合起来可以提高速度。但是,当然,您可以获得的最好结果是将常数加速,因为输出的大小和原始代码一样都是平方的。
lv0,lv1 = lattice_vectors[0],lattice_vectors[1]
lv0_i = -num_vectors * lv0 + center_pix
lv1_orig = -num_vectors * lv1
lv1_j = lv1_orig
for i in xrange(-num_vectors,num_vectors):
for j in xrange(-num_vectors,num_vectors):
lp = lv0_i + lv1_j
if all(lower_bounds < lp) and all(lp < upper_bounds):
lattice_points.append(lp)
lv1_j += lv1
lv0_i += lv0
lv1_j = lv1_orig
计时器结果:
>>> t = Timer(\"generate_lattice(image_shape,lattice_vectors,orig=True)\",\"from __main__ import generate_lattice,image_shape\")
>>> print t.timeit(number=50)
5.20121788979
>>> t = Timer(\"generate_lattice(image_shape,orig=False)\",image_shape\")
>>> print t.timeit(number=50)
2.17463898659
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。