pytorch和Numpy 的广播机制高效计算矩阵之间两两距离
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import torch def pairwise_distance_broadcast(X, Y = None ): """ 使用广播机制计算两两欧几里得距离。 参数: X: 第一个张量,形状为 (m, d),表示 m 个 d 维向量。 Y: 第二个张量(可选),形状为 (n, d)。如果为 None,则计算 X 内部的两两距离。 返回: 距离矩阵,形状为 (m, n)。 """ if Y is None : Y = X # 扩展维度以支持广播 X_expanded = X.unsqueeze( 1 ) # 形状为 (m, 1, d) Y_expanded = Y.unsqueeze( 0 ) # 形状为 (1, n, d) # 计算两两距离 distance_matrix = torch.sqrt(torch. sum ((X_expanded - Y_expanded) * * 2 , dim = 2 )) # 形状为 (m, n) return distance_matrix # 示例 X = torch.tensor([[ 1.0 , 2.0 ], [ 3.0 , 4.0 ], [ 5.0 , 6.0 ]], dtype = torch.float32) Y = torch.tensor([[ 7.0 , 8.0 ], [ 9.0 , 10.0 ]], dtype = torch.float32) # 计算 X 和 Y 之间的两两距离 distances = pairwise_distance_broadcast(X, Y) print ( "X 和 Y 之间的两两距离:" ) print (distances) # 计算 X 内部的两两距离 internal_distances = pairwise_distance_broadcast(X) print ( "X 内部的两两距离:" ) print (internal_distances) |
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | '''求三维空间中两组点之间的两两距离''' import numpy as np # 第一组点,假设有四个点,位置如下 a = np.array([[ 0 , 0 , 0 ], [ 10 , 10 , 10 ], [ 20 , 20 , 20 ], [ 30 , 30 , 30 ]]) # 第二组点,假设有两个点,位置如下 b = np.array([[ 0 , 0 , 0 ], [ 10 , 10 , 10 ]]) # 计算距离 c = a[:, None , :] - b # 用None扩展维度,使其shape变为(4, 1, 3),b的shape是(2, 3), # 然后两个数组相减,此时会用到广播机制。 c的shape:(4, 2, 3) dist = np.sqrt(np. sum (c * c, axis = - 1 )) print (dist) # 输出如下: # [[ 0. 17.32050808] # [17.32050808 0. ] # [34.64101615 17.32050808] # [51.96152423 34.64101615]] |
广播机制的规则可参考:nupmy broadcast (广播)
======================================================================
以下是旧内容:
利用numpy可以很方便的计算两个二维数组之间的距离。二维数组之间的距离定义为:X的维度为(m, c),Y的维度为(n,c),Z为X到Y的距离数组,维度为(m,n)。且Z[0,0]是X[0]到Y[0]的距离。Z(a,b)为X[a]到Y[b]的距离。
例如: 计算 m*2 的矩阵与 n * 2 的矩阵中,m*2 的每一行到 n*2 的两两之间欧氏距离。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | ''' L2 = sqrt((x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2) ''' import numpy as np # ============= 方法一:不用循环 ==================== def L2_dist_1(cloud1, cloud2): m, n = len (cloud1), len (cloud2) cloud1 = np.repeat(cloud1, n, axis = 0 ) cloud1 = np.reshape(cloud1, (m, n, - 1 )) dist = np.sqrt(np. sum ((cloud1 - cloud2) * * 2 , axis = 2 )) return dist # ============= 方法二:用一重循环 ================== def L2_dist_2(cloud1, cloud2): m, n = len (cloud1), len (cloud2) dist = np.zeros((m, n), dtype = np. float ) for i in range (m): dist[i, :] = np.sqrt(np. sum ((cloud1[i, :] - cloud2) * * 2 , axis = 1 )) return dist # ============= 方法二:用两重循环 ================== def L2_dist_3(cloud1, cloud2): m, n = len (cloud1), len (cloud2) dist = np.zeros((m, n), dtype = np. float ) for i in range (m): for j in range (n): dist[i, j] = np.sqrt(np. sum ((cloud1[i, :] - cloud2[j, :]) * * 2 , axis = 0 )) return dist if __name__ = = '__main__' : a = np.array([[ 0 , 0 , 0 ], [ 10 , 10 , 10 ], [ 20 , 20 , 20 ], [ 30 , 30 , 30 ]]) b = np.array([[ 0 , 0 , 0 ], [ 10 , 10 , 10 ]]) print ( '不用循环:\n' , L2_dist_1(a, b)) print ( '用一重循环:\n' , L2_dist_2(a, b)) print ( '用两重循环:\n' , L2_dist_3(a, b)) |
程序运行结果:
分类:
Python
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通