numpy-2d 中接近点的快速融合(矢量化)
Fast fuse of close points in a numpy-2d (vectorized)
我有一个类似于此处提出的问题的问题:
simple way of fusing a few close points。我想用坐标的平均值替换彼此靠近的点。单元格中的接近度由用户指定(我说的是欧氏距离)。
就我而言,我有很多积分(大约 100 万)。此方法有效,但非常耗时,因为它使用双循环。
有没有更快的方法来检测和融合 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
的距离函数,例如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]])
注意
对于大样本,此方法可能会导致内存错误,因为它存储的是包含相对距离的完整矩阵。
如果你有大量的点,那么构建一个 k-D tree using scipy.spatial.cKDTree
可能会更快,然后查询它以查找比某个阈值更接近的点对:
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]])
这种方法的主要优点是您不需要计算数据集中每对点之间的距离。
我有一个类似于此处提出的问题的问题: simple way of fusing a few close points。我想用坐标的平均值替换彼此靠近的点。单元格中的接近度由用户指定(我说的是欧氏距离)。
就我而言,我有很多积分(大约 100 万)。此方法有效,但非常耗时,因为它使用双循环。
有没有更快的方法来检测和融合 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
的距离函数,例如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]])
注意
对于大样本,此方法可能会导致内存错误,因为它存储的是包含相对距离的完整矩阵。
如果你有大量的点,那么构建一个 k-D tree using scipy.spatial.cKDTree
可能会更快,然后查询它以查找比某个阈值更接近的点对:
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]])
这种方法的主要优点是您不需要计算数据集中每对点之间的距离。