创建距离矩阵?

38

我目前正在将数据读入一个数据框,它看起来像这样。

City         XCord    YCord   
Boston         5        2
Phoenix        7        3
New York       8        1
.....          .        .

我想从这些数据中创建一个欧几里得距离矩阵,显示所有城市对之间的距离,以便获得如下的结果矩阵:

             Boston    Phoenix   New York
Boston         0        2.236      3.162
Phoenix        2.236      0        2.236
New York       3.162    2.236        0

在我的实际数据框中有许多更多的城市和坐标,因此我需要能够以某种方式迭代所有城市对,并创建像上面所示的距离矩阵,但我不确定如何将所有城市配对并应用欧几里得距离公式?任何帮助都将不胜感激。


你已经有任何代码了吗?请提供至少一段代码,将这些距离读入内存,以便得到类似 cords[boston] = (5, 2) 的东西。 - pkacprzak
现在我正在读取这样的CSV文件: Data = pd.read_csv('C:\Users\Jerry\Desktop\cities.csv') - Jeremy
请参考:https://dev59.com/JFQK5IYBdhLWcg3wJMu0 - Daniel F
7个回答

54

我认为你对 distance_matrix 感兴趣。

例如:

创建数据:

import pandas as pd
from scipy.spatial import distance_matrix
    
data = [[5, 7], [7, 3], [8, 1]]
ctys = ['Boston', 'Phoenix', 'New York']
df = pd.DataFrame(data, columns=['xcord', 'ycord'], index=ctys)

输出:

          xcord ycord
Boston      5   7
Phoenix     7   3
New York    8   1

使用距离矩阵函数:

 pd.DataFrame(distance_matrix(df.values, df.values), index=df.index, columns=df.index)

结果:

          Boston    Phoenix     New York
Boston    0.000000  4.472136    6.708204
Phoenix   4.472136  0.000000    2.236068
New York  6.708204  2.236068    0.000000

15

如果您不想使用scipy,您可以通过以下方式利用列表理解:

dist = lambda p1, p2: sqrt(((p1-p2)**2).sum())
dm = np.asarray([[dist(p1, p2) for p2 in xy_list] for p1 in xy_list])

这个答案非常灵活,允许使用任何距离函数。感谢分享! - emil

8

我将提供一个纯Python的方法。

从math模块中导入sqrt函数:

from math import sqrt

假设您的坐标以以下方式保存在cords表中:

cords['Boston'] = (5, 2)

定义一个函数来计算两个给定的二维点之间的欧几里得距离:

def dist(a, b):
    d = [a[0] - b[0], a[1] - b[1]]
    return sqrt(d[0] * d[0] + d[1] * d[1])

将结果矩阵初始化为字典:

D = {}

for city1, cords1 in cords.items():
    D[city1] = {}
    for city2, cords2 in cords.items():
        D[city1][city2] = dist(cords1, cords2)

D是您得到的矩阵。

完整的源代码如下,以及打印出来的结果:

from math import sqrt

cords = {}
cords['Boston'] = (5, 2)
cords['Phoenix'] = (7, 3)
cords['New York'] = (8, 1)

def dist(a, b):
    d = [a[0] - b[0], a[1] - b[1]]
    return sqrt(d[0] * d[0] + d[1] * d[1]) 

D = {}

for city1, cords1 in cords.items():
    D[city1] = {}
    for city2, cords2 in cords.items():
        D[city1][city2] = dist(cords1, cords2)   

for city1, v in D.items():
    for city2, d in v.items():
        print city1, city2, d

结果:

Boston Boston 0.0
Boston New York 3.16227766017
Boston Phoenix 2.2360679775
New York Boston 3.16227766017
New York New York 0.0
New York Phoenix 2.2360679775
Phoenix Boston 2.2360679775
Phoenix New York 2.2360679775
Phoenix Phoenix 0.0

2

这是一个纯Python和numpy解决方案,用于生成距离矩阵。

可以跳过冗余计算(因为距离是对称的distance(a,b)distance(b,a)相同,因此不需要计算两次距离)。

data = [[5, 7], [7, 3], [8, 1]]
cities = ['Boston', 'Phoenix', 'New York']

# Euclidean distance between two points
from math import sqrt
dist = lambda a,b: sqrt((a[0]-b[0])**2+(a[1]-b[1])**2)

import numpy as np
n = len(data)
dist_matrix = np.zeros((n,n))    # initialize distance matrix to a square of zeros
for i in range(n):
    for j in range(i, n):
        dist_matrix[i,j] = dist(data[i], data[j])
        dist_matrix[j,i] = dist_matrix[i,j]       # for the symmetric part, no computation

现在,dist_matrix[i,j]city[i]city[j]之间的距离。

1
data = [[5, 7], [7, 3], [8, 1]]
ctys = ['Boston', 'Phoenix', 'New York']
df = pd.DataFrame(data, columns=['xcord', 'ycord'], index=ctys)

n_df=(df.values)
n_df

(df.values).shape

matrix=np.zeros(((df.values).shape[0],(df.values).shape[0]))
matrix


for i in range((df.values).shape[0]):
    for j in range((df.values).shape[0]):
        matrix[i,j]=np.sqrt(np.sum((n_df[i]-n_df[j])**2))
        #print('i',i,'j',j)


print(matrix)

你能否为提问者描述一下,为什么这种方法比已有的好答案更好或提供了一个很好的替代方案? - phalteman
什么是最小可复现示例?https://stackoverflow.com/help/minimal-reproducible-example - Nikolas Rieble

0

参考

import pandas as pd
import numpy as np

data = [[5, 7], [7, 3], [8, 1]]
ctys = ['Boston', 'Phoenix', 'New York']
df = pd.DataFrame(data, columns=['xcord', 'ycord'], index=ctys)
x, y = df.xcord.to_numpy(), df.ycord.to_numpy()
x_y = df.values

%%timeit
pd.DataFrame(
    np.hypot(
        np.subtract.outer(x, x),
        np.subtract.outer(y, y)
    ),
    index=df.index, columns=df.index
)
# 32.9 µs ± 102 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%%timeit
pd.DataFrame(distance_matrix(x_y, x_y), index=df.index, columns=df.index)
# 49.8 µs ± 330 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

与普通的自定义sqrt方法相比,hypot更能抵御溢出和下溢的影响。

下溢

i, j = 1e-200, 1e-200
np.sqrt(i**2+j**2)
# 0.0

溢出

i, j = 1e+200, 1e+200
np.sqrt(i**2+j**2)
# inf

无下溢

i, j = 1e-200, 1e-200
np.hypot(i, j)
# 1.414213562373095e-200

无溢出

i, j = 1e+200, 1e+200
np.hypot(i, j)
# 1.414213562373095e+200

0

在scipy中有一个函数:

scipy.spatial.distance.cdist()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接