使用 Pandas 计算欧几里得距离矩阵

14

我有一个包含城市、纬度和经度数据的.csv文件,格式如下:

CITY|LATITUDE|LONGITUDE
A|40.745392|-73.978364
B|42.562786|-114.460503
C|37.227928|-77.401924
D|41.245708|-75.881241
E|41.308273|-72.927887
我需要创建一个如下格式的距离矩阵(请忽略虚拟值):

我需要创建以下格式的距离矩阵(请忽略虚拟值):

         A         B         C         D         E   
A  0.000000  6.000000  5.744563  6.082763  5.656854  
B  6.000000  0.000000  6.082763  5.385165  5.477226  
C  1.744563  6.082763  0.000000  6.000000  5.385165
D  6.082763  5.385165  6.000000  0.000000  5.385165  
E  5.656854  5.477226  5.385165  5.385165  0.000000  

我已将数据加载到 pandas 数据框中,并创建了以下交叉连接:

import pandas as pd
df_A = pd.read_csv('lat_lon.csv', delimiter='|', encoding="utf-8-sig")
df_B = df_A
df_A['key'] = 1
df_B['key'] = 1 
df_C = pd.merge(df_A, df_B, on='key')  
  • 你能帮我创建上面那个矩阵结构吗?
  • 另外,有可能避免使用交叉连接吗?

1
你有计算欧几里得距离的算法吗? - StefanS
可能是用于Pandas数据帧行的距离矩阵的重复问题。 - IanS
@IanS,我认为这不是完全相同的问题(提供的欧几里得距离答案也不是最快的 - 因为它使用了“apply”方法)。 - MaxU - stand with Ukraine
距离计算本身并不难,一旦我们有了城市的三维坐标,但由于我们没有高程信息,我们需要假设一个球体或某种地球形状。困难的部分并不是一个编程问题,因此我问OP是否已经有了算法。 - StefanS
3个回答

20
您可以使用pdistsquareform方法,它们来自于scipy.spatial.distance库:
In [12]: df
Out[12]:
  CITY   LATITUDE   LONGITUDE
0    A  40.745392  -73.978364
1    B  42.562786 -114.460503
2    C  37.227928  -77.401924
3    D  41.245708  -75.881241
4    E  41.308273  -72.927887

In [13]: from scipy.spatial.distance import squareform, pdist

In [14]: pd.DataFrame(squareform(pdist(df.iloc[:, 1:])), columns=df.CITY.unique(), index=df.CITY.unique())
Out[14]:
           A          B          C          D          E
A   0.000000  40.522913   4.908494   1.967551   1.191779
B  40.522913   0.000000  37.440606  38.601738  41.551558
C   4.908494  37.440606   0.000000   4.295932   6.055264
D   1.967551  38.601738   4.295932   0.000000   2.954017
E   1.191779  41.551558   6.055264   2.954017   0.000000

3
我从未使用过pdist,但根据文档,它使用2D欧几里得范数,这要求坐标在平面上并且具有距离单位,而对于经度和纬度值来说这两个条件都不成立。 - StefanS
2
@StefanS,OP想要使用“欧几里得距离”——这是非常明确的,并且在pdist中是默认方法。如果您或OP想要另一种方法(闵可夫斯基、城市街区、标准化欧几里得、平方欧几里得、余弦、相关性、汉明、杰卡德、切比雪夫、堪培拉等——总共有22种不同的度量),您可以将其指定为“metric”参数。 - MaxU - stand with Ukraine
唯有 OP 能真正知道他想要什么。但是欧几里得距离是明确定义的。如果你在球面/大地上有经度和纬度,你首先需要用长度来测量实际坐标,否则你的“距离”不仅取决于点之间的相对距离,还取决于在球体上的绝对位置(朝向极点时,同样的角度距离会变成更短的长度距离)。无论如何,这部分不是一个编程问题。一旦我们知道 OP 想从 lon/lat 转换为 3D 坐标的算法,我们就可以构建他的矩阵。 - StefanS
“Vincenty”是一个选项吗? - Sergio Lucero
@SergioLucero,当然可以使用“Vincenty”或haversine公式,但这不是问题的主要“问题”... - MaxU - stand with Ukraine

2

可以直接使用scipy.spatial.distance中的cdist创建矩阵:


最初的回答
from scipy.spatial.distance import cdist
df_array = df[["LATITUDE", "LONGITUDE"]].to_numpy()
dist_mat = cdist(df_array, df_array)
pd.DataFrame(dist_mat, columns = df["CITY"], index = df["CITY"])

1
for i in df["CITY"]:
    for j in df["CITY"]:
        row = df[df["CITY"] == j][["LATITUDE", "LONGITUDE"]]
        latitude = row["LATITUDE"].tolist()[0]
        longitude = row["LONGITUDE"].tolist()[0]
        df.loc[df['CITY'] == i, j] = ((df["LATITUDE"] - latitude)**2 + (df["LONGITUDE"] - longitude)**2)**0.5

df = df.drop(["CITY", "LATITUDE", "LONGITUDE"], axis=1)

这个有效


不,这只计算经度和纬度值的欧几里得范数(其单位为角度)。那不是欧几里得距离。 - StefanS
@StefanS 在二维空间中,它们之间有什么不同?(范数和距离公式) - Himaprasoon

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