【问题标题】:Fastest way to compute distances between consecutive vectors with numpy/scipy用 numpy/scipy 计算连续向量之间距离的最快方法
【发布时间】:2020-02-18 01:55:33
【问题描述】:

我有一个需要的线增长算法:

  • 计算数组中连续向量之间的距离(欧几里得)
  • 插入距离大于特定阈值的新向量

我通常以非常幼稚的方式执行此操作(请参阅下面的代码),并且想知道如何使用 numpy 以最快的方式计算连续向量之间的距离(如果需要,还可以使用 scipy)。

import math


threshold = 10
vectorList = [(0, 10), (4, 8), (14, 14), (16, 19), (35, 16)]

for i in xrange(len(vectorList)):
    p1 = vectorList[i]
    p2 = vectorList[i+1]
    d = math.sqrt((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2)
    if d >= threshold:
        pmid = ((p1[0] + p2[0]) * .5, (p1[1] + p2[1]) * .5)
        vectorList.insert(i+1, pmid)

编辑: 我想出了以下解决方法,但我仍然关心距离计算。

我需要计算一个向量与其在列表中的下一个邻居之间的距离,而不是像我在这里所做的那样计算整个距离矩阵(所有向量彼此相对)。

import numpy as np

vectorList = [(0, 10), (4, 8), (14, 14), (16, 19), (35, 16)]
arr = np.asarray(vectorList).astype(float)


dis = distance.cdist(arr, arr).diagonal(1)
idx = np.where(dis > 10)[0]
vec = (arr[idx] + arr[idx+1]) * .5
arr = np.insert(arr, idx+1, vec, 0)

# output
array([[ 0. , 10. ],[ 4. ,  8. ],[ 9. , 11. ],[14. , 14. ],[16. , 19. ],[25.5, 17.5],[35. , 16. ]])

【问题讨论】:

  • 这段代码能否可靠地处理vectorList的增长?
  • 对于给定的 vectorList 转换为二维数组,通过快速 numpy 计算应该很容易得到 dnp.diff 可能会给你一个起点)。但是逐步添加元素会更难。
  • 在插入后的循环中,i 应该是什么,或者更确切地说,p1 应该是什么? pmid 值?上一次迭代的p2?您可能需要添加另一个元组来测试它。
  • @hpaulj 感谢您的指点和对迟到的回复表示歉意。 np.diff 似乎计算向量之间的差异,而不是距离。如果我错了,请纠正我。问题已更新。
  • 我的意思是diff 作为起点。您的距离计算使用差异。

标签: python python-2.7 numpy distance insertion


【解决方案1】:
In [209]: vectorList = [(0, 10), (4, 8), (14, 14), (16, 19), (35, 16), (39,50)] 
In [210]: vectorList                                                            
Out[210]: [(0, 10), (4, 8), (14, 14), (16, 19), (35, 16), (39, 50)]

我添加了一个点,使 3 个可能的插入点。

In [212]: np.diff(vectorList, axis=0)                                           
Out[212]: 
array([[ 4, -2],
       [10,  6],
       [ 2,  5],
       [19, -3],
       [ 4, 34]])
In [213]: np.sum(np.diff(vectorList, axis=0)**2,1)                              
Out[213]: array([  20,  136,   29,  370, 1172])

距离:

In [214]: np.sqrt(np.sum(np.diff(vectorList, axis=0)**2,1))                     
Out[214]: array([ 4.47213595, 11.66190379,  5.38516481, 19.23538406, 34.23448554])

平均值:

In [216]: arr = np.array(vectorList)                                            
In [217]: arr                                                                   
Out[217]: 
array([[ 0, 10],
       [ 4,  8],
       [14, 14],
       [16, 19],
       [35, 16],
       [39, 50]])

In [218]: (arr[:-1]+arr[1:])/2                                                  
Out[218]: 
array([[ 2. ,  9. ],
       [ 9. , 11. ],
       [15. , 16.5],
       [25.5, 17.5],
       [37. , 33. ]])

没有diff,我也可以做类似的事情:

d = np.sqrt(np.sum((arr[1:]-arr[:-1])**2,1)) 

超过阈值的跳跃次数:

In [224]: idx = np.nonzero(d>10)                                                
In [225]: idx                                                                   
Out[225]: (array([1, 3, 4]),)
In [227]: _218[idx]       # the mean values to insert                                                            
Out[227]: 
array([[ 9. , 11. ],
       [25.5, 17.5],
       [37. , 33. ]])

使用np.insert 插入所有值。

In [232]: np.insert(arr.astype(float), idx[0]+1, _227, axis=0)                  
Out[232]: 
array([[ 0. , 10. ],
       [ 4. ,  8. ],
       [ 9. , 11. ],
       [14. , 14. ],
       [16. , 19. ],
       [25.5, 17.5],
       [35. , 16. ],
       [37. , 33. ],
       [39. , 50. ]])

【讨论】:

  • 谢谢,这很有帮助。
【解决方案2】:

这是使用 sklearn 的方法NearestNeighbors

from sklearn.neighbors import NearestNeighbors
import numpy as np

def distance(p1,p2):
    return np.sqrt(np.sum(np.diff([p1,p2], axis=0)**2,1))

def find_shortest_distance(vectorList):
    nbrs = NearestNeighbors(n_neighbors=2, metric=distance).fit(vectorList)
    distances, indices = nbrs.kneighbors(vectorList)

    result = distances[:, 1]
    return result

vectorList = [(0, 10), (4, 8), (14, 14), (16, 19), (35, 16)]

返回:

result
Out[57]: array([ 4.47213595,  4.47213595,  5.38516481,  5.38516481, 19.23538406])

这对于您的问题可能有点过分,但此解决方案不要求点按连续顺序排列。

时间(比 numpy 慢):

%timeit find_shortest_distance(vectorList)
478 µs ± 2.68 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

【讨论】:

  • 这确实有点矫枉过正,但我​​很欣赏这个建议+我学到了一些东西。也感谢您提供时间。
猜你喜欢
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 2021-04-18
  • 1970-01-01
  • 1970-01-01
  • 2018-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多