1 概述
两个向量之间的距离(此时向量作为n维坐标系中的点)计算,在数学上称为向量的距离(Distance),也称为样本之间的相似性度量(Similarity Measurement)。它反映为某类事物在距离上接近或远离的程度。直觉上,距离越近的就越相似,越容易归为一类;距离越远越不同。
2 常用距离及其python实现
2.1 闵可夫斯基距离(Minkowski Distance)
严格意义上讲,闵可夫斯基距离不是一种距离,而是一组距离的定义。两个n维变量A(x11,x12,...,x1n)与B(x21,X22,…,X2n)间的闵可夫斯基距离定义为:
其中p是一个变参数,根据变参数的不同,闵可夫斯基距离可以表示一类的距离。
- 当p=1时,就是曼哈顿距离。
- 当p=2时,就是欧氏距离。
- 当p->∞时,就是切比雪夫距离。
2.2 欧氏距离(Euclidean Distance)
欧氏距离(L2范数)是最易于理解的一种距离计算方法,源自欧氏空间中两点间的距离公式。两个n维向量A(x11,x12,…,x1n)与B(x21,x22,…,x2n)间的欧氏距离如下:
表示为向量运算的形式:
Python 实现欧式距离:
# 欧式距离
import numpy as np
v1 = np.mat([1,2,3])
v2 = np.mat([4,5,6])
print(np.sqrt((v1 - v2)*(v1 - v2).T))
输出结果为:[[5.19615242]]
2.3 曼哈顿距离(Manhattan Distance)
从名字就可以猜出这种距离的计算方法了。想象你在曼哈顿要从一个十字路口开车到另外一个十字路口,驾驶距离是两点间的直线距离吗?显然不是,除非你能穿越大楼。实际驾驶距离就是这个“曼哈顿距离”(L1范数),而这也是曼哈顿距离名称的来源。曼哈顿距离也称为城市街区距离(City Block distance),如下图所示。
两个n维向量A(x1,x12,…,x1n)与B(x21,x22,…,x2n)间的曼哈顿距离:
Python实现曼哈顿距离如下:
#曼哈顿距离
import numpy as np
v1 = np.mat([1,2,3])
v2 = np.mat([4,5,6])
print(np.sum(abs(v1 - v2)))
输出结果为:9
2.4 切比雪夫距离(Chebyshev Distance)
国际象棋玩过吗?国王走一步能够移动到相邻的8个方格中的任意一个,如下图所示。那么国王从格子(x1,y1)走到格子(x2,y2)最少需要多少步?自己走走试试。你会发现最少步数总是max(|x2-x1|,|y2-y1|)步。有一种类似的距离度量方法叫作切比雪夫距离(L∞范数)。
两个n维向量A(x1,x12,…,x1n)与B(x21,x22,…,x2n)间的切比雪夫距离:
这个公式的另一种等价形式是:
Python实现切比雪夫距离如下;
# 契比雪夫距离
import numpy as np
v1 = np.array([1,2,3])
v2 = np.array([4,7,5])
print(abs(v1 - v2).max())
输出结果为:5
2.5 夹角余弦(Cosine)
几何中的夹角余弦可用来衡量两个向量方向的差异,机器学习中借用这一概念来衡量样本向量之间的差异。对于两个n维样本点A(x11,x12,…,x1n)与B(x21,x22,…x2n),可以使用类似于夹角余弦的概念来衡量它们间的相似程度。
即:
夹角余弦取值范围为[-1,1]。夹角余弦越大,表示两个向量的夹角越小;夹角余弦越小,表示两个向量的夹角越大。当两个向量的方向重合时,夹角余弦取最大值1;当两个向量的方向完全相反时,夹角余弦取最小值-1。
Python实现夹角余弦如下:
# 夹角余余弦
import numpy as np
v1 = np.array([1,2,3])
v2 = np.array([4,7,5])
cosV12 = np.dot(v1,v2)/(np.linalg.norm(v1) * np.linalg.norm(v2))
print(cosV12)
输出结果为:0.9296696802013682
2.6 汉明距离(Hamming Distance)
汉明距离的定义:两个等长字符串s1与s2之间的汉明距离定义为将其中一个变为另外一个所需要的最小替换次数。例如字符串“1111”与“1001”之间的汉明距离为2。
Python实现汉明距离如下:
#汉明距离
import numpy as np
matV = np.mat([[1,1,0,1,0,1,0,0,1],[0,1,1,0,0,0,1,1,1]])
smstr = np.nonzero(matV[0]-matV[1])
print(smstr)
print(np.shape(smstr[0])[0])
输出结果为:
(array([0, 0, 0, 0, 0, 0], dtype=int64), array([0, 2, 3, 5, 6, 7], dtype=int64))
6
补充:np.nonzero()返回值为元组, 两个值分别为两个维度的下标值,即:(0,0),(0,2),(0,3),(0,5),(0,6),(0,7)为非零值,。
2.7 杰卡德相似系数(Jaccard Similarity Coefficient)
杰卡德相似系数:两个集合A和B的交集元素在A、B的并集中所占的比例,称为两个集合的杰卡德相似系数,用符号J(4,B)表示。杰卡德相似系数是衡量两个集合的相似度的一种指标。
杰卡德距离:与杰卡德相似系数相反的概念是杰卡德距离(Jaccard Distance),杰卡德距离用两个集合中不同元素占所有元素的比例来衡量两个集合的区分度。杰卡德距离可用如下公式表示:
样本A与样本B是两个n维向量,而且所有维度的取值都是0或1。例如,A(0111)和B(1011)。我们将样本看成一个集合,1表示集合包含该元素,0表示集合不包含该元素。
- P:样本A与B都是1的维度的个数。
- g:样本A是1、样本B是0的维度的个数。
- r:样本A是0、样本B是1的维度的个数。
- s:样本A与B都是0的维度的个数。
那么样本A与B的杰卡德相似系数可以表示为:
Python实现杰卡德距离如下:
# 杰卡德距离
import numpy as np
import scipy.spatial.distance as dist
matV = np.mat([[1,1,0,1,0,1,0,0,1],[0,1,1,0,0,0,1,1,1]])
print("dist.jaccard:",dist.pdist(matV,"jaccard"))
输出结果为:dist.jaccard: [0.75]
3 补充
细心的同学可能会发现上边的代码,有的使用np.mat(),有的使用np.array(),那么两者之间的区别是什么呢?
Numpy matrices必须是2维的,但是 numpy arrays (ndarrays) 可以是多维的(1D,2D,3D····ND)。Matrix是Array的一个小的分支,包含于Array。所以matrix 拥有array的所有特性。
在numpy中matrix的主要优势是:相对简单的乘法运算符号。例如,a和b是两个matrices,那么a*
b,就是矩阵积。相反的是在numpy里面arrays遵从逐个元素的运算,c*
d运算相当于matlab里面的c.*
d运算,而矩阵相乘,则需要numpy里面的dot命令 。
import numpy as np
a=np.mat('4 3; 2 1')
b=np.mat('1 2; 3 4')
c=np.array([[4, 3], [2, 1]])
d=np.array([[1, 2], [3, 4]])
print(a*b)
# [[13 20]
# [ 5 8]]
print(c*d)
# [[4 6]
# [6 4]]
print(np.dot(c,d))
# [[13 20]
# [ 5 8]]
matrix 和 array 都可以通过objects后面加.T 得到其转置。但是 matrix objects 还可以在后面加 .H 得到共轭矩阵, 加 .I 得到逆矩阵。
**
运算符的作用也不一样 ,当a是个matrix时,a2返回的是a*a,相当于矩阵相乘。当c是array,c2相当于,c中的元素逐个求平方。
import numpy as np
a=np.mat('4 3; 2 1')
c=np.array([[4, 3], [2, 1]])
print(a**2)
# [[22 15]
# [10 7]]
print(c**2)
# [[16 9]
# [ 4 1]]
那么问题就出来了,如果一个程序里面既有matrix 又有array,会让人脑袋大。但是如果只用array,你不仅可以实现matrix所有的功能,还减少了编程和阅读的麻烦。