给定一个矩阵,计算距离矩阵是一个非常常见的需求,比如给定一个特征矩阵需要计算距离矩阵。自己写的话虽然简单每次写也往往很烦,而且自己写的代码效率过低了,使用scipy中的包的话无疑会好一点,具体来说,使用scipy.spatial.distance,该包的具体介绍可以看一下官网和这个博客。
下面贴一个我写的基于经纬度矩阵,计算两两间的距离的代码:
具体矩阵的形式是一个dataframe,一列是经度,一列是纬度,如下图所示,下面代码中的cam就是这个dataframe。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial.distance import pdist
from scipy import spatial
import math
# 定义通过经纬度计算直线距离的函数
from math import radians, cos, sin, asin, sqrt
def geodistance(lng1,lat1,lng2,lat2):
if lng1 == None or lng2 == None or lat1 == None or lat2 == None:
return 999999
elif (lng1 < 119 or lng1 > 121) or (lng2 < 119 or lng2 > 121) or (lat1 < 29 or lat1 > 30) or (lat2 < 29 or lat2 > 30):
return 999999
lng1 = float(lng1) ; lng2 = float(lng2) ; lat1 = float(lat1) ; lat2 = float(lat2)
lng1,lat1,lng2,lat2 = map(radians,[lng1,lat1,lng2,lat2])
dlon = lng2-lng1
dlat = lat2-lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
distance = 2* asin(sqrt(a))*6371*1000
distance = round(distance/1000,3)
return distance
def caldis(u,v):
# 计算输入矩阵中两个向量的距离
return geodistance(u[0],u[1],v[0],v[1])
# 将cam转化为向量的形式
X = cam.values
X_mat = spatial.distance.squareform(pdist(X , metric=caldis))
上面代码得到的X_mat就是每两个经纬度点之间的直线距离了。
下面我还希望求出这个距离矩阵中每一行中距离小于等于1的个数,并将这个个数保存到dataframe cam中去,代码如下:
def sma1(ser):
return (len(ser[ser<=1]))
cam['devdes'] = np.apply_along_axis(sma1, 1, X_mat)
如果不是一个矩阵各个样本两两间的距离,而是两个矩阵两两间的距离,则可以使用函数from scipy.spatial.distance import cdist,代码如下:
X_mat = cdist(cam[['lng','lat']].values , tmp[['lng','lat']].values , metric=caldis)
得到的结果是len(cam[[‘lng’,‘lat’]])行,len(tmp[[‘lng’,‘lat’]].values)列的一个矩阵,第i,j个元素代表的含义是cam[[‘lng’,‘lat’]]第i行和tmp[[‘lng’,‘lat’]]第j列两个元素的距离。