距离算法汇总及Python实现

1.欧氏距离

最常见的两点之间或多点之间的距离表示方法,又称之为欧几里得度量,它定义于欧几里得空间中,如点 x = ( x 1 , ⋅ ⋅ ⋅ , x n ) x=(x_1,···,x_n) x=(x1,,xn) y = ( y 1 , ⋅ ⋅ ⋅ , y n ) y=(y_1,···,y_n) y=(y1,,yn)之间的距离为:
d ( x , y ) = ( x 1 − y 1 ) 2 + ( y 2 − y 2 ) 2 + ⋅ ⋅ ⋅ + ( x n − y n ) 2 d(x,y)=\sqrt{(x_1-y_1)^2+(y_2-y_2)^2+···+(x_n-y_n)^2} d(x,y)=(x1y1)2+(y2y2)2++(xnyn)2

1.1 二维平面上两点a(x1,y1)与b(x2,y2)间的欧氏距离:
d 12 = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 d_{12}=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2} d12=(x1x2)2+(y1y2)2
1.2 三维空间两点a(x1,y1,z1)与b(x2,y2,z2)间的欧氏距离:
d 12 = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 + ( z 1 − z 2 ) 2 d_{12}=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2} d12=(x1x2)2+(y1y2)2+(z1z2)2
1.3 两个n维向量a(x11,x12,…,x1n)与 b(x21,x22,…,x2n)间的欧氏距离

d 12 = ∑ k = 1 n ( x 1 k − x 2 k ) 2 d_{12}=\sqrt{\sum_{k=1}^n{(x_{1k}-x_{2k})^2}} d12=k=1n(x1kx2k)2
也可以用表示成向量运算的形式:
d 12 = ( a − b ) ( a − b ) T d_{12}=\sqrt{(a-b)(a-b)^T} d12=(ab)(ab)T

其上,二维平面上两点欧式距离,代码可以如下编写:
C++实现:

//unixfy:计算欧氏距离
double euclideanDistance(const vector<</span>double>& v1, const vector<</span>double>& v2)
	{
	assert(v1.size() == v2.size());
	double ret = 0.0;
	for (vector<</span>double>::size_type i = 0; i != v1.size(); ++i)
	{
		ret += (v1[i] - v2[i]) * (v1[i] - v2[i]);
	}
	return sqrt(ret);
}

Python实现:

import numpy as np
x=np.random.random(10)
y=np.random.random(10)

#方法一:根据公式求解
d1=np.sqrt(np.sum(np.square(x-y)))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
X=np.vstack([x,y])
d2=pdist(X)

2.曼哈顿距离

我们可以定义曼哈顿距离的正式意义为L1-距离或城市区块距离,也就是在欧几里得空间的固定直角坐标系上两点所形成的线段对轴产生的投影的距离总和。例如在平面上,坐标(x1, y1)的点P1与坐标(x2, y2)的点P2的曼哈顿距离为: ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ |x_1-x_2|+|y_1-y_2| x1x2+y1y2,要注意的是,曼哈顿距离依赖座标系统的转度,而非系统在座标轴上的平移或映射。
  通俗来讲,想象你在曼哈顿要从一个十字路口开车到另外一个十字路口,驾驶距离是两点间的直线距离吗?显然不是,除非你能穿越大楼。而实际驾驶距离就是这个“曼哈顿距离”,此即曼哈顿距离名称的来源,同时,曼哈顿距离也称为城市街区距离(City Block distance)。
1.1 二维平面两点a(x1,y1)与b(x2,y2)间的曼哈顿距离:
∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ |x_1-x_2|+|y_1-y_2| x1x2+y1y2
1.2 两个n维向量a(x11,x12,…,x1n)与 b(x21,x22,…,x2n)间的曼哈顿距离:
d 12 = ∑ k = 1 n ∣ x 1 k − x 2 k ∣ d_{12}=\sum_{k=1}^n{|x_{1k}-x_{2k}|} d12=k=1nx1kx2k
Python实现:

import numpy as np
x=np.random.random(10)
y=np.random.random(10)

#方法一:根据公式求解
d1=np.sum(np.abs(x-y))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
X=np.vstack([x,y])
d2=pdist(X,'cityblock')

3.切比雪夫距离

若两个向量或两个点p和q,其座标分别为 p i p_i pi q i q_i qi,则两者之间的切比雪夫距离定义如下:
D c h e b y s h e v ( p , q ) = max ⁡ i ( ∣ p i − q i ∣ ) D_{chebyshev(p,q)}=\max_i(|p_i-q_i|) Dchebyshev(p,q)=imax(piqi)
这也等于以下 L p L_p Lp度量的极值,因此切比雪夫距离也称 L ∞ L\infty L度量
lim ⁡ k → ∞ ( ∑ i = 1 n ∣ p i − q i ∣ k ) 1 / k \lim_{k\rightarrow\infty}(\sum_{i=1}^n|p_i-q_i|^k)^{1/k} klim(i=1npiqik)1/k
以数学的观点来看,切比雪夫距离是由一致范数(uniform norm)(或称为上确界范数)所衍生的度量,也是超凸度量(injective metric space)的一种。
在平面几何中,若二点p及q的直角坐标系坐标为 ( x i , y i ) (x_i,y_i) (xi,yi) ( x 2 , y 2 ) (x_2,y_2) (x2,y2),则切比雪夫距离为:
D c h e s s = m a x ( ∣ x 2 − x 1 ∣ , ∣ y 2 − y 1 ∣ ) D_{chess}=max(|x_2-x_1|,|y_2-y_1|) Dchess=max(x2x1,y2y1)
玩过国际象棋的朋友或许知道,国王走一步能够移动到相邻的8个方格中的任意一个。那么国王从格子(x1,y1)走到格子(x2,y2)最少需要多少步?你会发现最少步数总是max( | x2-x1 | , | y2-y1 | ) 步 。有一种类似的一种距离度量方法叫切比雪夫距离。
1.1 二维平面两点a(x1,y1)与b(x2,y2)间的切比雪夫距离:
D 12 = m a x ( ∣ x 1 − x 2 ∣ , ∣ y 1 − y 2 ∣ ) D_{12}=max(|x_1-x_2|,|y_1-y_2|) D12=max(x1x2,y1y2)
1.2 两个n维向量a(x11,x12,…,x1n)与 b(x21,x22,…,x2n)间的切比雪夫距离   
D 12 = max ⁡ i ( ∣ x 1 i − x 2 i ∣ ) D_{12}=\max_i(|x_{1i}-x_{2i}|) D12=imax(x1ix2i)
这个公式的另一种等价形式是
d 12 = lim ⁡ k → ∞ ( ∑ i = 1 n ∣ x 1 i − x 2 i ∣ k ) 1 / k d_{12}=\lim_{k\rightarrow\infty}(\sum_{i=1}^n|x_{1i}-x_{2i}|^k)^{1/k} d12=klim(i=1nx1ix2ik)1/k

Python实现:

import numpy as np
x=np.random.random(10)
y=np.random.random(10)

#方法一:根据公式求解
d1=np.max(np.abs(x-y))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
X=np.vstack([x,y])
d2=pdist(X,'chebyshev')

4.闵可夫斯基

距离
闵氏距离(Minkowski Distance)不是一种距离,而是一组距离的定义。
两个n维变量a(x11,x12,…,x1n)与 b(x21,x22,…,x2n)间的闵可夫斯基距离定义为:
d 12 = ∑ k = 1 n ∣ x 1 k − x 2 k ∣ p p d_{12}=\sqrt[p]{\sum_{k=1}^n|x_{1k}-x_{2k}|^p} d12=pk=1nx1kx2kp
其中p是一个变参数。
当p=1时,就是曼哈顿距离
当p=2时,就是欧氏距离
p → ∞ p\rightarrow\infty p时,就是切比雪夫距离
根据变参数的不同,闵氏距离可以表示一类的距离。
Python实现:

import numpy as np
x=np.random.random(10)
y=np.random.random(10)

#方法一:根据公式求解,p=2
d1=np.sqrt(np.sum(np.square(x-y)))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
X=np.vstack([x,y])
d2=pdist(X,'minkowski',p=2)

5.标准化欧氏距离

标准化欧氏距离(Standardized Euclidean distance )是针对简单欧氏距离的缺点而作的一种改进方案。标准欧氏距离的思路:既然数据各维分量的分布不一样,那先将各个分量都“标准化”到均值、方差相等。至于均值和方差标准化到多少,先复习点统计学知识。
假设样本集X的数学期望或均值(mean)为m,标准差(standard deviation,方差开根)为s,那么X的“标准化变量”X*表示为:(X-m)/s,而且标准化变量的数学期望为0,方差为1。即,样本集的标准化过程(standardization)用公式描述就是:
X ∗ = X − m s X*=\frac{X-m}{s} X=sXm
标准化后的值 = ( 标准化前的值 - 分量的均值 ) /分量的标准差
经过简单的推导就可以得到两个n维向量a(x11,x12,…,x1n)与 b(x21,x22,…,x2n)间的标准化欧氏距离的公式:
d 12 = ∑ k = 1 n ( x 1 k − x 2 k s k ) 2 d_{12}=\sqrt{\sum_{k=1}^n{(\frac{x_{1k}-x_{2k}}{s_k})^2}} d12=k=1n(skx1kx2k)2
如果将方差的倒数看成是一个权重,这个公式可以看成是一种加权欧氏距离(Weighted Euclidean distance)。
python实现:

import numpy as np
x=np.random.random(10)
y=np.random.random(10)

X=np.vstack([x,y])

#方法一:根据公式求解
sk=np.var(X,axis=0,ddof=1)
d1=np.sqrt(((x - y) ** 2 /sk).sum())

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
d2=pdist(X,'seuclidean')

6.马氏距离

马氏距离定义
有M个样本向量 X 1 X_1 X1~ X m X_m Xm,协方差矩阵记为S,均值记为向量 μ \mu μ,则其中样本向量X到 μ \mu μ的马氏距离表示为:
D ( X ) = ( X − μ ) T S − 1 ( X − μ ) D(X)=\sqrt{(X-\mu)^TS^{-1}(X-\mu)} D(X)=(Xμ)TS1(Xμ)
而其中向量 X i X_i Xi X j X_j Xj之间的马氏距离定义为:
D ( X i , X j ) = ( X i − X j ) T S − 1 ( X i − X j ) D(X_i,X_j)=\sqrt{(X_i-X_j)^TS^{-1}(X_i-X_j)} D(Xi,Xj)=(XiXj)TS1(XiXj)
若协方差矩阵是单位矩阵(各个样本向量之间独立同分布),则公式就成了:
D ( X i , X j ) = ( X i − X j ) T ( X i − X j ) D(X_i,X_j)=\sqrt{(X_i-X_j)^T(X_i-X_j)} D(Xi,Xj)=(XiXj)T(XiXj)
也就是欧式距离了。
Python中实现:

import numpy as np
x=np.random.random(10)
y=np.random.random(10)

#马氏距离要求样本数要大于维数,否则无法求协方差矩阵
#此处进行转置,表示10个样本,每个样本2维
X=np.vstack([x,y])
XT=X.T

#方法一:根据公式求解
S=np.cov(X)   #两个维度之间协方差矩阵
SI = np.linalg.inv(S) #协方差矩阵的逆矩阵
#马氏距离计算两个样本之间的距离,此处共有10个样本,两两组合,共有45个距离。
n=XT.shape[0]
d1=[]
for i in range(0,n):
   for j in range(i+1,n):
       delta=XT[i]-XT[j]
       d=np.sqrt(np.dot(np.dot(delta,SI),delta.T))
       d1.append(d)
       
#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
d2=pdist(XT,'mahalanobis')

马氏优缺点:

1)马氏距离的计算是建立在总体样本的基础上的,这一点可以从上述协方差矩阵的解释中可以得出,也就是说,如果拿同样的两个样本,放入两个不同的总体中,最后计算得出的两个样本间的马氏距离通常是不相同的,除非这两个总体的协方差矩阵碰巧相同;

2)在计算马氏距离过程中,要求总体样本数大于样本的维数,否则得到的总体样本协方差矩阵逆矩阵不存在,这种情况下,用欧式距离计算即可。

3)还有一种情况,满足了条件总体样本数大于样本的维数,但是协方差矩阵的逆矩阵仍然不存在,比如三个样本点(3,4),(5,6)和(7,8),这种情况是因为这三个样本在其所处的二维空间平面内共线。这种情况下,也采用欧式距离计算。

4)在实际应用中“总体样本数大于样本的维数”这个条件是很容易满足的,而所有样本点出现3)中所描述的情况是很少出现的,所以在绝大多数情况下,马氏距离是可以顺利计算的,但是马氏距离的计算是不稳定的,不稳定的来源是协方差矩阵,这也是马氏距离与欧式距离的最大差异之处。

优点:它不受量纲的影响,两点之间的马氏距离与原始数据的测量单位无关;由标准化数据和中心化数据(即原始数据与均值之差)计算出的二点之间的马氏距离相同。马氏距离还可以排除变量之间的相关性的干扰。缺点:它的缺点是夸大了变化微小的变量的作用。

原文链接:https://www.cnblogs.com/denny402/p/7027954.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值