python中不同大小列表中坐标的有效欧几里得距离



我有两个大点列表。一个包含表示矩形边缘的点 (edge_points)。Edge_points具有 XY 坐标。另一个列表包含矩形 (all_point) 内的点。All_point具有 XYZ 坐标。在第二个列表中,我想删除边缘周围点的xy"m"距离内的任何点(列表1)。

我有一个有效的代码,但它很慢,嵌套循环...我见过建议 cdist 的线程,但这不适用于我想将矩形中的每个点与单个边缘点进行比较的方案。Hypot 比使用 sqrt 更快,但仍然无法让我达到我想要的位置。

如何提高此代码的效率?

all_point=colpoint+rowpoint
all_points=[]
for n in range(0,len(all_point)):
#Calculate xy distance between inflection point and edge points
test_point=all_point[n]
dist=[]
for k in range(0,len(edge_points)):
test_edge=edge_points[k]
dist_edge=math.hypot((test_point[1]-test_edge[1])+(test_point[0]-test_edge[0]))
dist.append(dist_edge)
if all(i >= m for i in dist) is True:
all_points.append(test_point)
else:
continue

Vectorise,vectorise也适用于这里:

import numpy as np
all_point, edge_points = np.asanyarray(all_point), np.asanyarray(edge_points)
squared_dists = ((all_point[:, None, :2] - edge_points[None, :, :])**2).sum(axis=-1)
mask = np.all(squared_dists > m**2, axis=-1)
all_points = all_point[mask, :]

请注意,在 Python 级别没有更多的循环。矢量化将这些循环移动到编译的代码,其执行速度提高了几倍。

具体来说,我们创建了两个数组all_point大小N1x2和大小edge_pointsN2x2.然后将它们重新塑造为N1x1x21xN2x2的大小(通过索引中的None秒)。

当取差值时,这会触发前两个轴的广播,使得生成的数组具有形状N1xN2x2,并包含all_pointedge_points坐标之间的所有成对差异。随后的平方一次性应用于所有N1xN2x2元素。由axis参数指定的总和沿最后一个轴取,即超过xy以产生一个N1xN2的平方成对距离数组。

接下来的几行演示了if语句的矢量化等效项。为了能够一次性执行它们,人们会创建真相面具。与m**2的比较是按元素完成的,因此我们得到了squared_dists的每个N1xN2元素的真值。np.all类似于Pythonall,但可以同时执行多个组。这由axis参数控制。在这里,它指定应按行应用all,以产生N1真值。

此掩码在形状上与all_point匹配,可用于提取满足条件的所有坐标对。

总结广播允许从Python级别消除嵌套循环并将其替换为一些矢量化操作。只要内存不是问题,就会带来巨大的加速。

如果内存是一个问题:这是一个使用tensordot的节省内存的变体

all_point, edge_points = np.asanyarray(all_point), np.asanyarray(edge_points)
mixed = np.tensordot(all_point[:, :2], -2 * edge_points, (1, 1))
mixed += (all_point[:, :2]**2).sum(axis=-1)[:, None]
mixed += (edge_points**2).sum(axis=-1)[None, :]
mask = np.all(mixed > m**2, axis=-1)
all_points = all_point[mask, :]

如果它仍然太大,我们将不得不将all_pointedge_points切成可管理的部分。

all_point, edge_points = np.asanyarray(all_point), np.asanyarray(edge_points)
mask = np.ones((len(all_point),), dtype=bool)
mm = m*m - (all_point[:,:2]**2).sum(axis=-1)[:, None]
chunksize = <choose according to your memory and data size>
for i in range(0, len(edge_points), chunksize):
mixed = np.tensordot(all_point[mask, :2], -2 * edge_points[i:i+chunksize, :], (1, 1))
mixed += (edge_points[None, i:i+chunksize, :]**2).sum(axis=-1)
mask[mask] &= np.all(mixed > mm[mask], axis=-1)
all_points = all_point[mask, :]

最新更新