当前位置: 首页 > 面试题库 >

Python,成对的“距离”,需要一种快速的方法来实现

司空朝
2023-03-14
问题内容

对于我的博士学位的副项目,我从事用Python建模某些系统的任务。在效率方面,我的程序遇到了以下问题的瓶颈,我将在“最小工作示例”中介绍该问题。

我处理大量由其3D起点和终点编码的线段,因此每个线段均由6个标量表示。

我需要计算成对的最小段间距离。在此来源中找到了两个线段之间的最小距离的解析表达式。致MWE:

import numpy as np
N_segments = 1000
List_of_segments = np.random.rand(N_segments, 6)

Pairwise_minimal_distance_matrix = np.zeros( (N_segments,N_segments) )
for i in range(N_segments):
    for j in range(i+1,N_segments):

        p0 = List_of_segments[i,0:3] #beginning point of segment i
        p1 = List_of_segments[i,3:6] #end point of segment i
        q0 = List_of_segments[j,0:3] #beginning point of segment j
        q1 = List_of_segments[j,3:6] #end point of segment j
        #for readability, some definitions
        a = np.dot( p1-p0, p1-p0)
        b = np.dot( p1-p0, q1-q0)
        c = np.dot( q1-q0, q1-q0)
        d = np.dot( p1-p0, p0-q0)
        e = np.dot( q1-q0, p0-q0)
        s = (b*e-c*d)/(a*c-b*b)
        t = (a*e-b*d)/(a*c-b*b)
        #the minimal distance between segment i and j
        Pairwise_minimal_distance_matrix[i,j] = sqrt(sum( (p0+(p1-p0)*s-(q0+(q1-q0)*t))**2)) #minimal distance

现在,我意识到这是非常低效的,这就是为什么我在这里。我已经广泛研究了如何避免循环,但是遇到了一个问题。显然,这种计算最好用python的cdist完成。但是,它可以处理的自定义距离函数必须是二进制函数。在我的情况下,这是一个问题,因为我的向量的长度具体为6,并且必须按位分割为它们的前3个分量。我认为我无法将距离计算转换为二进制函数。

任何输入表示赞赏。


问题答案:

您可以使用numpy的矢量化功能来加快计算速度。我的版本一次计算距离矩阵的所有元素,然后将对角线和下三角设置为零。

def pairwise_distance2(s):
    # we need this because we're gonna divide by zero
    old_settings = np.seterr(all="ignore")

    N = N_segments # just shorter, could also use len(s)

    # we repeat p0 and p1 along all columns
    p0 = np.repeat(s[:,0:3].reshape((N, 1, 3)), N, axis=1)
    p1 = np.repeat(s[:,3:6].reshape((N, 1, 3)), N, axis=1)
    # and q0, q1 along all rows
    q0 = np.repeat(s[:,0:3].reshape((1, N, 3)), N, axis=0)
    q1 = np.repeat(s[:,3:6].reshape((1, N, 3)), N, axis=0)

    # element-wise dot product over the last dimension,
    # while keeping the number of dimensions at 3
    # (so we can use them together with the p* and q*)
    a = np.sum((p1 - p0) * (p1 - p0), axis=-1).reshape((N, N, 1))
    b = np.sum((p1 - p0) * (q1 - q0), axis=-1).reshape((N, N, 1))
    c = np.sum((q1 - q0) * (q1 - q0), axis=-1).reshape((N, N, 1))
    d = np.sum((p1 - p0) * (p0 - q0), axis=-1).reshape((N, N, 1))
    e = np.sum((q1 - q0) * (p0 - q0), axis=-1).reshape((N, N, 1))

    # same as above
    s = (b*e-c*d)/(a*c-b*b)
    t = (a*e-b*d)/(a*c-b*b)

    # almost same as above
    pairwise = np.sqrt(np.sum( (p0 + (p1 - p0) * s - ( q0 + (q1 - q0) * t))**2, axis=-1))

    # turn the error reporting back on
    np.seterr(**old_settings)

    # set everything at or below the diagonal to 0
    pairwise[np.tril_indices(N)] = 0.0

    return pairwise

现在让我们旋转一下。以您的示例N = 1000为准,

%timeit pairwise_distance(List_of_segments)
1 loops, best of 3: 10.5 s per loop

%timeit pairwise_distance2(List_of_segments)
1 loops, best of 3: 398 ms per loop

当然,结果是一样的:

(pairwise_distance2(List_of_segments) == pairwise_distance(List_of_segments)).all()

返回True。我也很确定算法中的某个地方隐藏了一个矩阵乘法,因此应该有进一步加速(以及清理)的潜力。

顺便说一句:我尝试过首先简单地使用numba而不成功。虽然不知道为什么。



 类似资料:
  • 问题内容: 我有一个一维数字数组,想计算所有成对的欧几里得距离。我有一种方法(感谢SO)在广播中执行此操作,但是它效率低下,因为它两次计算每个距离。而且它的伸缩性不好。 这是一个示例,它为我提供了1000个数字的数组。 我可以使用scipy / numpy / scikit-learn中最快的实现来执行此操作,因为它必须扩展到一维数组具有> 10k值的情况。 注意:矩阵是对称的,所以我猜想通过解决

  • 注意:矩阵是对称的,所以我猜测,通过寻址它,至少有可能获得2倍的加速,我只是不知道如何实现。

  • 问题内容: 谁能帮我?我正在尝试提出一种计算方法 并计算此总和中的项目数,而不必进行两次以上的传递。 似乎令人难以置信,但是在扫描了std- lib(内置函数,itertools,functools等)后,我什至找不到一个可以计算可迭代对象数的函数。我发现了这个函数,听起来像我想要的,但实际上它只是一个虚假命名的函数。 经过一番思考,我想出了以下内容(它很简单,缺少库函数可能是可以原谅的,除了它的

  • 问题内容: 我想生成一个以字母作为键的字典,类似 生成该字典而不是我必须键入它的快速方法是什么? 谢谢你的帮助。 编辑 谢谢大家的解决方案:) nosklo的 解决方案可能是最短的 另外,感谢您提醒我有关Python字符串模块的信息。 问题答案: 我发现此解决方案更加优雅:

  • 问题内容: 顾名思义,我正在使用python编写的网站上,它对urllib2模块进行了多次调用以读取网站。然后,我用BeautifulSoup解析它们。 由于我必须阅读5-10个站点,因此页面需要一段时间才能加载。 我只是想知道是否可以同时阅读所有站点?还是任何使它更快的技巧,例如我应该在每次读取后关闭urllib2.urlopen还是将其保持打开状态? 补充 :另外,如果我只是改用php,从其他

  • 例如,计算欧氏距离:。这里,如果或的大小太小/太大,则可能发生下溢/溢出。 解决这一问题的常用方法是用最大的数量级除数。但是,这个解决方案是: 慢(除法慢) 导致一点额外的不准确 所以我想,不除以最大的星等数,让我们把它乘以一个接近的-2的倒数数。这似乎是一个更好的解决办法,因为: 乘法比除法快得多 精度更高,因为乘以2的幂数是精确的 此函数应返回一个规范化的和,两者都是2的幂数,其中接近于,而是

  • 我有一个小的基本问题。我用的是Mac电脑,我以前在办公室工作。py文件与升华3。我喜欢的一件事是,当Sublime关闭时,对于文件夹中的给定文件——如果我在寻找一些代码——我可以点击空格键,Mac电脑可以快速预览文件。py文件。 现在我在Jupyter笔记本中工作,并将所有内容保存为. ipynb文件。现在我不能点击空格键和浏览文件——我从命令区启动JN,它要慢得多。 我怀疑有更快的方法在浏览器窗

  • 本文向大家介绍Python实现快速多线程ping的方法,包括了Python实现快速多线程ping的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python实现快速多线程ping的方法。分享给大家供大家参考。具体如下: 执行结果: administrator@nagios:/win/pexpect$ ./ping.py [2011-04-25 21:30:22.126981] 192