1. 欧氏距离
欧几里得度量(euclidean metric)(也称欧氏距离)是一个通常采用的距离定义,指在m维空
间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。在二维和三维空间中
的欧氏距离就是两点之间的实际距离。
from scipy.spatial import distance
a = (1, 2, 3)
b = (4, 5, 6)
print(distance.euclidean(a, b))
2. 曼哈顿距离
图中红线代表曼哈顿距离,绿色代表欧氏距离,也就是直线距离,而蓝色和黄色代表等价的
曼哈顿距离。曼哈顿距离——两点在南北方向上的距离加上在东西方向上的距离,即d(i,j)=|xi-
xj|+|yi-yj|。对于一个具有正南正北、正东正西方向规则布局的城镇街道,从一点到达另一点的距离
正是在南北方向上旅行的距离加上在东西方向上旅行的距离,因此,曼哈顿距离又称为出租车距
离。曼哈顿距离不是距离不变量,当坐标轴变动时,点间的距离就会不同。曼哈顿距示意图在早期
的计算机图形学中,屏幕是由像素构成,是整数,点的坐标也一般是整数,原因是浮点运算很昂
贵,很慢而且有误差,如果直接使用AB的欧氏距离(欧几里德距离:在二维和三维空间中的欧氏
距离的就是两点之间的距离),则必须要进行浮点运算,如果使用AC和CB,则只要计算加减法即
可,这就大大提高了运算速度,而且不管累计运算多少次,都不会有误差。
import numpy as np
from scipy.spatial import distance
A = np.array([7,8,9])
B = np.array([4,5,6])
# 方式一:直接构造公式计算
dist1 = np.sum(np.abs(A-B))
# 方式二:内置线性代数函数计算
dist2 = np.linalg.norm(A-B,ord=1) #ord为范数类型,取值1(一范数),2(二范数),np.inf(无穷范数),默认2。
# 方式三:scipy库计算
dist3 = distance.cityblock(A,B)
3. 标准化欧氏距离
标准化欧⽒距离是针对欧⽒距离的缺点⽽作的⼀种改进。
既然数据各维分量的分布不⼀样,那先将各个分量都“标准化”到均值、⽅差相等。
S 表示各个维度的标准差:
如果将⽅差的倒数看成⼀个权重,也可称之为加权欧⽒距离(Weighted Euclidean distance)。
from scipy.spatial.distance import pdist
dist2 = pdist(Vec,’seuclidean’)
4. 余弦距离
⼏何中,夹⻆余弦可⽤来衡量两个向量⽅向的差异;机器学习中,借⽤这⼀概念来衡量样本向
量之间的差异。
⼆维空间中向量A(x1,y1)与向量B(x2,y2)的夹⻆余弦公式:
两个n维样本点a(x11,x12,…,x1n)和b(x21,x22,…,x2n)的夹⻆余弦为:
夹⻆余弦取值范围为[-1,1]。余弦越⼤表示两个向量的夹⻆越⼩,余弦越⼩表示两向量的夹⻆
越⼤。当两个向量的⽅向 重合时余弦取最⼤值1,当两个向量的⽅向完全相反余弦取最⼩值-1。
import numpy as np
from scipy.spatial import distance
A = np.array([7,8,9])
B = np.array([4,5,6])
# 方式一:直接构造公式计算
dist1 = np.sum(A*B)/(np.sqrt(np.sum(A**2))*np.sqrt(np.sum(B**2)))
# 方式二:scipy库计算
dist2 = 1-distance.cosine(A,B)
5. 汉明距离
两个等⻓字符串s1与s2的汉明距离为:将其中⼀个变为另外⼀个所需要作的最⼩字符替换次数。
汉明重量:是字符串相对于同样⻓度的零字符串的汉明距离,也就是说,它是字符串中⾮零的
元素个数,对于⼆进制字符串来说,就是 1 的个数,所以 11101 的汉明重量是 4。因此,向量空
间中的元素a和b之间的汉明距离等于它们汉明重量的差a-b。
应⽤:汉明重量分析在包括信息论、编码理论、密码学等领域都有应⽤。⽐如在信息编码过程中,
为了增强容错性,应使得编码间的最⼩汉明距离尽可能⼤。但是,如果要⽐较两个不同⻓度的字符
串,不仅要进⾏替换,⽽且要进⾏插⼊与删除的运算,在这种场合下,通常使⽤更加复杂的编辑距
离等算法。
import numpy as np
from scipy.spatial import distance
A = np.array([1,2,3])
B = np.array([4,5,6])
# scipy库计算
dist1 = distance.hamming(A,B)
6. 杰卡德距离
杰卡德相似系数(Jaccard similarity coefficient):两个集合A和B的交集元素在A,B的并集中所
占的⽐例,称为两个集合的杰卡德相似系数,⽤符号J(A,B)表示:
杰卡德距离(Jaccard Distance):与杰卡德相似系数相反,⽤两个集合中不同元素占所有元素
的⽐例来衡量两个集合的区分度:
# 方案一
# 根据公式求解
up = np.double(np.bitwise_and((vec1!=vec2),np.bitwise_or(vec1!=0,vec2!=0)).sum())
down = np.double(np.bitwise_or(vec1!=0,vec2!=0).sum())
dist1=(up/down)
print("杰卡德距离测试结果是:"+str(dist1))
# 方案二
# 根据scipy库求解
from scipy.spatial.distance import pdist
Vec = np.vstack([vec1,vec2])
dist2 = pdist(Vec,'jaccard')
print("杰卡德距离测试结果是:"+str(dist2))
7. 马氏距离
马氏距离是基于样本分布的⼀种距离。
马氏距离是由印度统计学家⻢哈拉诺⽐斯提出的,表示数据的协⽅差距离。它是⼀种有效的计算两
个位置样本集的相似 度的⽅法。 与欧式距离不同的是,它考虑到各种特性之间的联系,即独⽴于
测量尺度。
马氏距离也可以定义为两个服从同⼀分布并且其协⽅差矩阵为∑的随机变量的差异程度,如果
协⽅差矩阵为单位矩阵, 马氏距离就简化为欧式距离;如果协⽅差矩阵为对角矩阵,则其也可称
为正规化的欧式距离。
计算马氏距离过程中,要求总体样本数⼤于样本的维数,否则得到的总体样本协⽅差矩阵逆矩阵不
存在,这种情况 下,⽤欧式距离计算即可。
import numpy as np
from scipy.spatial.distance import pdist
a=np.random.random(10)
b=np.random.random(10)
#马氏距离要求样本数要大于维数,否则无法求协方差矩阵
X=np.vstack([a,b])
XT=X.T #此处进行转置,表示10个样本,每个样本2维
pdist(XT,'mahalanobis')
8. 切比雪夫距离
在数学中,切比雪夫距离或是L∞度量,是向量空间中的一种度量,二个点之间的距离定义是
其各坐标数值差绝对值的最大值。以数学的观点来看,切比雪夫距离是由一致范数(uniform
norm)(或称为上确界范数)所衍生的度量,也是超凸度量(injective metric space)的一种。
# 根据scipy库求解
from scipy.spatial.distance import pdist
Vec = np.vstack([vec1,vec2])
dist2 = pdist(Vec,'chebyshev')
print('切比雪夫距离测试结果是:' + str(dist2))
9. 闵可夫斯基距离
闵可夫斯基距离 (Minkowski Distance),也被称为 闵氏距离。它不仅仅是一种距离,而是将多
个距离公式(曼哈顿距离、欧式距离、切比雪夫距离)总结成为的一个公式。
两个n维变量a(x11,x12,…,x1n)与b(x21,x22,…,x2n)间的闵可夫斯基距离定义为:
# 根据scipy库求解
from scipy.spatial.distance import pdist
Vec = np.vstack([vec1,vec2])
dist2 = pdist(Vec,'cityblock',p=1)
print('当P=1时就是曼哈顿距离,测试结果是:' + str(dist2))
# 根据公式求解,p=1
from numpy import *
dist3 = sum(abs(vec1-vec2))# abs()绝对值
print('当p=1时就是曼哈顿距离,测试结果是:' + str(dist3))
10. K-L散度
K-L散度(Kullback–Leibler divergence),又称K-L距离,相对熵。
当P(x)和Q(x)的相似度越高,K-L散度越小。
K-L散度主要有两个性质:
(1)不对称性
尽管KL散度从直观上是个度量或距离函数,但它并不是一个真正的度量或者距离,因为它不具有
对称性,即D(P||Q)!=D(Q||P)。
(2)非负性
相对熵的值是非负值,即D(P||Q)>0。
# 利用scipy API进行计算
KL = scipy.stats.entropy(x, y)
print(KL)
# 用公式编程就用px和py
KL = 0.0
for i in range(10):
KL += px[i] * np.log(px[i] / py[i])
print(KL)