You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中欧氏距离矩阵转阈值邻接表的代码性能优化方法

邻接表转换性能优化方案

需求说明

需要将12000个原子间的成对欧氏距离矩阵转换为节点邻接表:邻接表第i个元素为所有和第i个节点距离在指定阈值内的节点编号列表。
以3个二维点的计算逻辑为例:

  • 输入点坐标
(0,0) (1,0) (1,1)
  • 对应成对距离矩阵
[[0.         1.         1.41421356]
 [1.         0.         1.        ]
 [1.41421356 1.         0.        ]]
  • 距离阈值设为1时,满足距离<=1的索引对为
[[0 0]
 [0 1]
 [1 0]
 [1 1]
 [1 2]
 [2 1]
 [2 2]]
  • 最终输出邻接表
[[0,1],[0,1,2],[1,2]]

现有实现与性能瓶颈

当前可运行代码如下:

from scipy.spatial import distance
import numpy as np

def voisinage(xyz):
    # xyz为三维空间坐标数组
    # 计算全量成对距离矩阵
    dist = distance.cdist(xyz,xyz,'euclidean')
    # 提取距离小于阈值的索引对
    paires = np.argwhere(dist<threshold)
    # 初始化邻接表
    Vvoisinage = [[] for i in range(len(xyz))]
    # 逐对填充邻接表
    for p in paires:
        Vvoisinage[p[0]].append(p[1])
    return Vvoisinage

该代码处理12100个三维点耗时4-5秒,由于需要对数千组同规模点集批量运行,需要进一步提速。测试过networkx实现同逻辑,速度远慢于当前方案。
性能测试显示,最后逐行填充邻接表的Python循环平均耗时2.7秒,占总时长一半,是核心优化点,也接受整体逻辑层面的更优实现。

优化方案

1. 局部优化:替换Python层循环(不改动原有计算逻辑)

原有循环逐行遍历numpy数组、反复执行list append的开销极高,直接用numpy的分组操作拆分索引对,完全去掉Python层循环即可:

from scipy.spatial import distance
import numpy as np

def voisinage_fast_local(xyz, threshold):
    dist = distance.cdist(xyz, xyz, 'euclidean')
    paires = np.argwhere(dist < threshold)
    # 按源节点i排序后直接拆分,得到每个节点的邻居数组
    Vvoisinage = np.split(paires[:,1], np.unique(paires[:,0], return_index=True)[1][1:])
    # 需要Python原生list格式时打开下一行注释
    # return [list(arr) for arr in Vvoisinage]
    return Vvoisinage

这部分优化可以把原来2.7秒的填充环节压缩到0.2秒以内。

2. 全局优化:替换O(n²)全量距离计算(性能提升10~20倍)

12000个点的全量距离矩阵是12000*12000的float64数组,光存储就要占1.1GB左右内存,cdist的O(n²)计算本身也是耗时大头。直接用scipy的cKDTree做半径邻域查询,平均复杂度O(n),不需要生成全量距离矩阵,整体耗时可以压到0.3秒以内:

from scipy.spatial import cKDTree
import numpy as np

def voisinage_fast_global(xyz, threshold):
    tree = cKDTree(xyz)
    # 直接查询每个点阈值范围内的所有邻居,返回邻接表
    return tree.query_ball_point(xyz, r=threshold, workers=-1)

注:workers=-1会调用所有CPU核心并行计算,批量处理时如果要控制CPU占用可以调整该参数。默认query_ball_point返回结果包含自身节点,和原代码逻辑一致;如果需要排除自身节点,遍历每个邻接列表移除等于自身索引的元素即可。

性能对比(12100个三维点测试)

  • 原实现:4.5秒左右
  • 局部优化版:1.8秒左右
  • cKDTree全局优化版:0.2~0.3秒

内容的提问来源于stack exchange,提问作者Jacques

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 15:54:07