">

编程数学之距离计算

摘要:数学在计算机科学、机器学习、深度学习、自然语言处理等多个领域占据比较重要的位置。比如:特征值和特征向量在PCA降维中会使用;均值在回归算法中估计公式参数中使用;期望和均值在回归方程应用;余弦定理求相似度中运用;拉格朗日定理在支持向量机中使用;求导在解决梯度下降中使用;矩阵和向量在数据格式转换和预处理中运用等等。还有在算法建模、参数设置、验证策略、识别欠拟合和过拟合等方面依然应用广泛。本系列数学文章旨在带领大家快速回顾常用知识,重在理解。(本文原创,转载必须注明出处.)


余弦距离

形式化描述

余弦夹角也可以叫余弦相似度。 几何中夹角余弦可用来衡量两个向量方向的差异,机器学习中借用这一概念来衡量样本向量之间的差异。余弦取值范围为[-1,1]。求得两个向量的夹角,并得出夹角对应的余弦值,此余弦值就可以用来表征这两个向量的相似性。夹角越小,趋近于0度,余弦值越接近于1,它们的方向更加吻合,则越相似。当两个向量的方向完全相反夹角余弦取最小值-1。当余弦值为0时,两向量正交,夹角为90度。因此可以看出,余弦相似度与向量的幅值无关,只与向量的方向相关。

公式化描述

  • 在二维空间中向量A(x1,y1)与向量B(x2,y2)的夹角余弦公式

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np
vec1 = [1,2,3,4]
vec2 = [5,6,7,8]

#方法一:根据公式求解
dist1=np.dot(vec1,vec2)/(np.linalg.norm(vec1)*np.linalg.norm(vec2))
print("余弦距离测试结果是:\t"+str(dist1))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
Vec=np.vstack([vec1,vec2])
dist2=1-pdist(Vec,'cosine')
print("余弦距离测试结果是:\t"+str(dist2))

欧氏距离

形式化描述

在数学中,欧几里得距离或欧几里得度量是欧几里得空间中两点间“普通”(即直线)距离。使用这个距离,欧氏空间成为度量空间。相关联的范数称为欧几里得范数。较早的文献称之为毕达哥拉斯度量。

公式化描述

  • 维平面上两点\( a(x_1,y_1) \)与\( b(x_2,y_2)\)间的欧氏距离:
  • 三维空间两点\( a(x_1,y_1,z_1)\)与\( b(x_2,y_2,z_1)\)间的欧氏距离:
  • 两个n维向量\(a(x_1,x_2,…,x_n)\)与\(b(y_1,y_2,…,y_n)\)间的欧氏距离:

  • 表示成向量运算的形式:\(d_{12}=\sqrt{(a-b)(a-b)^{T}}\)

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np
vec1 =np.mat([1,2,3,4])
vec2 =np.mat([5,6,7,8])

#方法一:根据公式求解
dist1=np.sqrt(np.sum(np.square(vec1-vec2)))
print("欧氏距离测试结果是:\t"+str(dist1))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
Vec=np.vstack([vec1,vec2])
dist2=pdist(Vec)
print("欧氏距离测试结果是:\t"+str(dist2))

# 方法三:根据公式求解
from numpy import *
dist3 = sqrt((vec1-vec2)*(vec1-vec2).T)
print("欧氏距离测试结果是:\t"+str(dist3))

曼哈顿距离

形式化描述

计程车几何或曼哈顿距离或方格线距离是由十九世纪的赫尔曼·闵可夫斯基所创辞汇,为欧几里得几何度量空间的几何学之用语,用以标明两个点上在标准坐标系上的绝对轴距之总和。简言之,曼哈顿从一个十字路口开车到另外一个十字路口,驾驶距离不是两点间的直线距离。实际驾驶距离就是这个“曼哈顿距离”。而这也是曼哈顿距离名称的来源, 曼哈顿距离也称为城市街区距离(City Block distance)。

公式化描述

二维平面两点a

  • (x1,y1)与b(x2,y2)间的曼哈顿距离:
  • 两个n维向量\( a(x_1,x_2,…,x_n)\)与\( b(y_1,y_2,…,y_n)\)间的曼哈顿距离:

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
vec1 = np.mat([1,2,3,4])
vec2 = np.mat([5,6,7,8])

#方法一:根据公式求解
dist1=np.sum(np.abs(vec1-vec2))
print("曼哈顿距离测试结果是:\t"+str(dist1))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
Vec=np.vstack([vec1,vec2])
dist2=pdist(Vec,'cityblock')
print("曼哈顿距离测试结果是:\t"+str(dist2))

from numpy import *
dist3 = sum(abs(vec1-vec2))
print("曼哈顿距离测试结果是:\t"+str(dist3))

明可夫斯基距离

形式化描述

明氏距离又叫做明可夫斯基距离,是欧氏空间中的一种测度,被看做是欧氏距离和曼哈顿距离的一种推广。

公式化描述

  • 两个n维向量\(a(x_1,x_2,…,x_n)\)与\(b(y_1,y_2,…,y_n)\)间的明可夫斯基距离:

也可以写成:

其中p是一个变参数。

  1. 当p=1时,就是曼哈顿距离
  2. 当p=2时,就是欧氏距离
  3. 当p→∞时,就是切比雪夫距离

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import numpy as np
vec1 = np.mat([1,2,3,4])
vec2 = np.mat([5,6,7,8])

#方法一:根据scipy库求解
from scipy.spatial.distance import pdist
Vec=np.vstack([vec1,vec2])
dist2=pdist(Vec,'minkowski',p=1)
print("当p=1时就是曼哈顿距离,结果是:\t"+str(dist2))

#方法二:根据公式求解,p=2
dist1=np.sqrt(np.sum(np.square(vec1-vec2)))
print("当p=2时就是欧式距离,结果是:\t"+str(dist1))

from numpy import *
#方法三:根据公式求解,p=1
dist3 = sum(abs(vec1-vec2))
print("当p=1时就是曼哈顿距离,结果是:\t"+str(dist3))

#方法四:根据公式求解,p=2
dist4 = sqrt((vec1-vec2)*(vec1-vec2).T)
print("当p=2时就是欧式距离,测试结果是:\t"+str(dist4))

切比雪夫距离

形式化描述

数学上,切比雪夫距离(Chebyshev distance)是向量空间中的一种度量,二个点之间的距离定义为其各座标数值差的最大值。以(x1,y1)和(x2,y2)二点为例,其切比雪夫距离为max(|x2-x1|,|y2-y1|)。切比雪夫距离得名自俄罗斯数学家切比雪夫。

公式化描述

  • 二维平面两点\(a(x_1,y_1)\)与\(b(x_2,y_2)\)间的切比雪夫距离:
  • 两个n维向量\(a(x_1,x_2,…,x_n)\)与\(b(y_1,y_2,…,y_n)\)间的切比雪夫距离:

还可以表示为:

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np
vec1 = np.mat([1,2,3,4])
vec2 = np.mat([5,6,7,8])

#方法一:根据公式求解
dist1=np.max(np.abs(vec1-vec2))
print("切比雪夫距离测试结果是:\t"+str(dist1))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
Vec=np.vstack([vec1,vec2])
dist2=pdist(Vec,'chebyshev')
print("切比雪夫距离测试结果是:\t"+str(dist2))

杰卡德距离

形式化描述

杰卡德相似系数:两个集合A和B的交集元素在A,B的并集中所占的比例,称为两个集合的杰卡德相似系数,用符号J(A,B)表示。

杰卡德距离:与杰卡德相似系数相反的概念即杰卡德距离用两个集合中不同元素占所有元素的比例来衡量两个集合的区分度。这是杰卡德距离(Jaccard distance)。

杰卡德相似系数与杰卡德距离的应用: 可将杰卡德相似系数用在衡量样本的相似度上。样本A与样本B是两个n维向量,而且所有维度的取值都是0或1。例如:A(0111)和B(1011)。我们将样本看成是一个集合,1表示集合包含该元素,0表示集合不包含该元素。

公式化描述

  • 杰卡德相似系数公式化表示:

  • 杰卡德距离可用如下公式表示:

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np
v1=np.random.random(10)>0.5
v2=np.random.random(10)>0.5

vec1=np.asarray(v1,np.int32)
vec2=np.asarray(v2,np.int32)

#方法一:根据公式求解
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("杰卡德距离测试结果是:\t"+str(dist1))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
Vec=np.vstack([vec1,vec2])
dist2=pdist(Vec,'jaccard')
print("杰卡德距离测试结果是:\t"+str(dist2))

汉明距离

形式化描述

在信息论中,两个等长字符串之间的汉明距离是两个字符串对应位置的不同字符的个数。换句话说,它就是将一个字符串变换成另外一个字符串所需要替换的字符个数。

范例公式化描述

  • 1011101与1001001之间的汉明距离是2。
  • 2143896与2233796之间的汉明距离是3。
  • “toned”与”roses”之间的汉明距离是3。

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
v1=np.random.random(10)>0.5
v2=np.random.random(10)>0.5

vec1=np.asarray(v1,np.int32)
vec2=np.asarray(v2,np.int32)

#方法一:根据公式求解
dist1=np.mean(vec1!=vec2)
print("汉明距离测试结果是:\t"+str(dist1))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
Vec=np.vstack([vec1,vec2])
dist2=pdist(Vec,'hamming')
print("汉明距离测试结果是:\t"+str(dist2))

标准化欧式距离

形式化描述

标准化欧氏距离是针对简单欧氏距离的缺点而作的一种改进方案。标准欧氏距离的思路:既然数据各维分量的分布不一样,那我先将各个分量都“标准化”到均值、方差相等。均值和方差标准化到多少呢?这里先复习点统计学知识吧,假设样本集X的均值(mean)为m,标准差(standard deviation)为s,那么X的“标准化变量”表示为:

标准化后的值 = ( 标准化前的值 - 分量的均值 ) /分量的标准差

公式化描述

两个n维向量\(a(x_1,x_2,…,x_n)\)与\(b(y_1,y_2,…,y_n)\)间的标准化欧氏距离的公式:

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
vec1 = np.array([1,2,3,4])
vec2 = np.array([5,6,7,8])

Vec=np.vstack([vec1,vec2])
#方法一:根据公式求解
sk=np.var(Vec,axis=0,ddof=1)
dist1=np.sqrt(((vec1 - vec2) ** 2 /sk).sum())
print("标准化欧氏距离测试结果是:\t"+str(dist1))

#方法二:根据scipy库求解
from scipy.spatial.distance import pdist
dist2=pdist(Vec,'seuclidean')
print("标准化欧氏距离测试结果是:\t"+str(dist2))

皮尔逊相关系数

形式化描述

在统计学中,皮尔逊积矩相关系数(英语:Pearson product-moment correlation coefficient,常用r表示)用于度量两个变量X和Y之间的相关(线性相关),其值介于-1与1之间。在自然科学领域中,该系数广泛用于度量两个变量之间的相关程度。

公式化描述

夹角余弦公式写成:

向量x和向量y之间的夹角余弦,则皮尔逊相关系数则可表示为:

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
vec1 = np.array([1,2,3,4])
vec2 = np.array([5,6,7,8])


#方法一:根据公式求解
vec1_=vec1-np.mean(vec1)
vec2_=vec2-np.mean(vec2)
dist1=np.dot(vec1_,vec2_)/(np.linalg.norm(vec1_)*np.linalg.norm(vec2_))
print("皮尔逊相关系数测试结果是:\t"+str(dist1))

#方法二:根据numpy库求解
Vec=np.vstack([vec1,vec2])
dist2=np.corrcoef(Vec)[0][1]
print("皮尔逊相关系数测试结果是:\t"+str(dist2))

参考文献

  1. Python官网
  2. 中文维基百科
  3. GitHub
  4. 图书:《机器学习实战》
  5. 图书:《自然语言处理理论与实战》

完整代码下载

源码请进【机器学习和自然语言QQ群:436303759】文件下载:自然语言处理和机器学习技术QQ交流

作者声明

本文版权归作者所有,旨在技术交流使用。未经作者同意禁止转载,转载后需在文章页面明显位置给出原文连接,否则相关责任自行承担。

白宁超 wechat
扫一扫关注微信公众号,机器学习和自然语言处理,订阅号datathinks!