我是Python的新手,所以这个问题可能看起来很琐碎。但是,我没有找到类似的情况。我有一个20个节点的坐标矩阵。我想计算此集合中所有节点对之间的欧氏距离,并将它们存储在成对矩阵中。例如,如果我有20个节点,我希望最终结果是(20,20)的矩阵,每个节点对之间的欧几里德距离值。我尝试使用for循环遍历坐标集的每个元素并计算欧氏距离,如下所示:
ncoord=numpy.matrix('3225 318;2387 989;1228 2335;57 1569;2288 8138;3514 2350;7936 314;9888 4683;6901 1834;7515 8231;709 3701;1321 8881;2290 2350;5687 5034;760 9868;2378 7521;9025 5385;4819 5943;2917 9418;3928 9770')
n=20
c=numpy.zeros((n,n))
for i in range(0,n):
for j in range(i+1,n):
c[i][j]=math.sqrt((ncoord[i][0]-ncoord[j][0])**2+(ncoord[i][1]-ncoord[j][1])**2)
然而,我收到的错误是"输入必须是方阵 &#34 ;.我想知道是否有人知道这里发生了什么。 感谢
答案 0 :(得分:7)
使用嵌套for
循环有很多,更快的替代方法。我将向您展示两种不同的方法 - 第一种将是一种更为通用的方法,它将向您介绍广播和矢量化,第二种方法将使用更方便的scipy库函数。
我建议做的第一件事就是切换到使用np.array
而不是np.matrix
。数组是a number of reasons的首选,最重要的是因为它们可以具有> 2维,并且它们使元素乘法更加笨拙。
import numpy as np
ncoord = np.array(ncoord)
使用数组,我们可以通过插入新的单例维度和broadcasting减法来消除嵌套的for
循环:
# indexing with None (or np.newaxis) inserts a new dimension of size 1
print(ncoord[:, :, None].shape)
# (20, 2, 1)
# by making the 'inner' dimensions equal to 1, i.e. (20, 2, 1) - (1, 2, 20),
# the subtraction is 'broadcast' over every pair of rows in ncoord
xydiff = ncoord[:, :, None] - ncoord[:, :, None].T
print(xydiff.shape)
# (20, 2, 20)
这相当于使用嵌套for循环遍历每对行,但更快,更快!
xydiff2 = np.zeros((20, 2, 20), dtype=xydiff.dtype)
for ii in range(20):
for jj in range(20):
for kk in range(2):
xydiff[ii, kk, jj] = ncoords[ii, kk] - ncoords[jj, kk]
# check that these give the same result
print(np.all(xydiff == xydiff2))
# True
其余的我们也可以使用矢量化操作:
# we square the differences and sum over the 'middle' axis, equivalent to
# computing (x_i - x_j) ** 2 + (y_i - y_j) ** 2
ssdiff = (xydiff * xydiff).sum(1)
# finally we take the square root
D = np.sqrt(ssdiff)
整个事情可以在这样的一行中完成:
D = np.sqrt(((ncoord[:, :, None] - ncoord[:, :, None].T) ** 2).sum(1))
pdist
事实证明,已经有一个快速便捷的函数来计算所有成对距离:scipy.spatial.distance.pdist
。
from scipy.spatial.distance import pdist, squareform
d = pdist(ncoord)
# pdist just returns the upper triangle of the pairwise distance matrix. to get
# the whole (20, 20) array we can use squareform:
print(d.shape)
# (190,)
D2 = squareform(d)
print(D2.shape)
# (20, 20)
# check that the two methods are equivalent
print np.all(D == D2)
# True
答案 1 :(得分:4)
for i in range(0, n):
for j in range(i+1, n):
c[i, j] = math.sqrt((ncoord[i, 0] - ncoord[j, 0])**2
+ (ncoord[i, 1] - ncoord[j, 1])**2)
注意:ncoord[i, j]
与Numpy 矩阵的ncoord[i][j]
不同。这似乎是混乱的根源。如果ncoord
是Numpy 数组,那么他们会得到相同的结果。
对于Numpy 矩阵,ncoord[i]
返回ncoord
的第行,其本身是Numpy 矩阵在您的情况下形状为1 x 2的物体。因此,ncoord[i][j]
实际上意味着:获取ncoord
的第i行和获取该第1行的第j行 2 矩阵。这是j
>时出现索引问题的地方。 0
关于分配给c[i][j]
“工作”的意见,不应该。至少在我的Numpy 1.9.1版本中,如果您的索引i
和j
迭代到n
,它就不会起作用。
另外,请记住将矩阵c
的转置添加到自身。
建议使用Numpy数组而不是矩阵。请参阅this post。
如果您的坐标存储为Numpy数组,则成对距离可以计算为:
from scipy.spatial.distance import pdist
pairwise_distances = pdist(ncoord, metric="euclidean", p=2)
或只是
pairwise_distances = pdist(ncoord)
因为默认度量标准是“euclidean”,默认“p”是2。
在下面的评论中,我错误地提到了pdist的结果是一个n x n矩阵。 要获得n x n矩阵,您需要执行以下操作:
from scipy.spatial.distance import pdist, squareform
pairwise_distances = squareform(pdist(ncoord))
或
from scipy.spatial.distance import cdist
pairwise_distances = cdist(ncoord, ncoord)
答案 2 :(得分:0)
我想你想做什么:你说你想要一个20乘20的矩阵......但是你编码的那个是三角形的。
因此,我编写了一个完整的20x20矩阵。
distances = []
for i in range(len(ncoord)):
given_i = []
for j in range(len(ncoord)):
d_val = math.sqrt((ncoord[i, 0]-ncoord[j,0])**2+(ncoord[i,1]-ncoord[j,1])**2)
given_i.append(d_val)
distances.append(given_i)
# distances[i][j] = distance from i to j
SciPy方式:
from scipy.spatial.distance import cdist
# Isn't scipy nice - can also use pdist... works in the same way but different recall method.
distances = cdist(ncoord, ncoord, 'euclidean')