【问题标题】:Fast fuse of close points in a numpy-2d (vectorized)numpy-2d(矢量化)中闭合点的快速融合
【发布时间】:2016-08-27 09:07:31
【问题描述】:

我有一个与此处提出的问题类似的问题: simple way of fusing a few close points。我想用坐标的平均值替换彼此靠近的点。单元格的接近度由用户指定(我说的是欧几里德距离)。

就我而言,我有很多积分(大约 100 万)。此方法有效,但由于使用双 for 循环,因此比较耗时。

有没有更快的方法来检测和融合 numpy 二维数组中的闭合点?


为了完整起见,我添加了一个示例:

points=array([[  382.49056159,   640.1731949 ],
   [  496.44669161,   655.8583119 ],
   [ 1255.64762859,   672.99699399],
   [ 1070.16520917,   688.33538171],
   [  318.89390168,   718.05989421],
   [  259.7106383 ,   822.2       ],
   [  141.52574427,    28.68594436],
   [ 1061.13573287,    28.7094536 ],
   [  820.57417943,    84.27702407],
   [  806.71416007,   108.50307828]])

点的散点图如下所示。红色圆圈表示彼此靠近的点(在这种情况下,数组中最后两个点之间的距离为 27.91)。因此,如果用户指定最小距离为 30,则应融合这些点。

在 fuse 函数的输出中,最后一个 to 点被融合。这看起来像:

#output
array([[  382.49056159,   640.1731949 ],
   [  496.44669161,   655.8583119 ],
   [ 1255.64762859,   672.99699399],
   [ 1070.16520917,   688.33538171],
   [  318.89390168,   718.05989421],
   [  259.7106383 ,   822.2       ],
   [  141.52574427,    28.68594436],
   [ 1061.13573287,    28.7094536 ],
   [  813.64416975,    96.390051175]])

【问题讨论】:

  • scipy.spatial.cKDTree 是它所在的位置

标签: python arrays numpy scipy distance


【解决方案1】:

您可以使用scipy 的距离函数如pdist 以便快速找到应该合并的点:

import numpy as np
from scipy.spatial.distance import pdist, squareform

d = squareform(pdist(a))
d = np.ma.array(d, mask=np.isclose(d, 0))
a[d.min(axis=1) < 30]
#array([[ 820.57417943,   84.27702407],
#       [ 806.71416007,  108.50307828]])

注意

对于大样本,此方法可能会导致内存错误,因为它存储的是包含相对距离的完整矩阵。

【讨论】:

  • @Mehdi,感谢您的 cmets,确实对于大型样本,这将面临内存问题,但它仍然是一项有用的资产。我更新了答案以解决您的言论
  • 只是对 OP 状况的提示(大约 100 万分)
【解决方案2】:

如果您有大量点,那么使用scipy.spatial.cKDTree 构建k-D tree 可能会更快,然后在其中查询比某个阈值更近的点对:

import numpy as np
from scipy.spatial import cKDTree

tree = cKDTree(points)
rows_to_fuse = tree.query_pairs(r=30)    

print(repr(rows_to_fuse))
# {(8, 9)}

print(repr(points[list(rows_to_fuse)]))
# array([[ 820.57417943,   84.27702407],
#        [ 806.71416007,  108.50307828]])

这种方法的主要优点是您不需要计算数据集中每对点之间的距离。

【讨论】:

  • 您能详细说明一下吗?为什么有 .pop() ?我尝试了我的数据集,我总是得到一个形状为 (2, 2) 的结果数组。
  • @Mehdi rows_to_fuse 是一个 Python set 包含 (i, j) 元组,其中 ijpoints 中距离为 rows_to_fuse.pop() 从集合中删除任意元组并返回它(在这种情况下,集合中只有一个元组),然后我将它转换为一个列表并用于索引到 pairs 的行以检索 x、y该对的坐标。最终结果是一个(2, 2) numpy 数组,但rows_to_fuse 是一个集合。如果我将rows_to_fuse 直接转换为列表,可能会更清楚。
  • 我的情况缺少另一行,fused_scans = np.mean(fused_scans, 1) 这得到了对的平均值。
  • 很好的答案,作为建议,您可以将参数 output_type='ndarray' 添加到 query_pairs 调用中,以获取数组而不是集合的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多