各种距离相似度量及计算

各类算法中,距离是一个经常使用的量,经常会与各种相似性计算联系在一起。下面我们来总结一下各种距离与相似的计算。

1.欧式距离

欧式距离是我们最常用的距离度量之一,指在空间中两个点的真实距离长度,或者向量自身长度。
对于欧式距离,无须太多解释,直接看代码就可以。

import math
import numpy as np
from scipy.spatial.distance import pdist

def euclidean_distance():
	x = np.array([1, 2, 3, 4])
	y = np.array([5, 6, 7, 8])
	distance = np.sqrt(sum(math.pow(a - b, 2) for a, b in zip(x, y)))
	print(f'distance is: {distance}')
	distance = np.sqrt(sum(np.square(x - y)))
	print(f'distance is: {distance}')
	xy = np.vstack([x, y])
	distance = pdist(xy)
	print(f'distance is: {distance[0]}')

输出结果为:

distance is: 8.0
distance is: 8.0
distance is: 8.0

2.标准化欧式距离

常规版的欧式距离没有考虑到向量各个维度的差异。如果向量各个维度的差异很大,会导致距离计算时候数值较大的分量占主导。比如两个向量a、b,a=(1,10), b=(2, 20),如果使用标准的欧式距离计算方式,第二维分量是第一维的十倍,此时整个距离计算第二维分量就占主要作用,第一维的影响很小。

为了解决上述问题,我们可以对每一维分量进行标准化处理。假设某一维分量为x, 均值为 μ \mu μ,标准差为s,则标准化公式为
x ∗ = x − μ s x^* = \frac{x - \mu}{s} x=sxμ

有两个n维向量a, b, a = ( x 1 , x 2 , ⋯   , x n ) , b = ( y 1 , y 2 , ⋯   , y n ) a = (x_1,x_2,\cdots,x_n), b = (y_1,y_2,\cdots,y_n) a=(x1,x2,,xn),b=(y1,y2,,yn), 则ab的标准化欧式距离为
d ( a , b ) = ∑ k = 1 n ( x k − y k s k ) 2 d(a, b) =\sqrt { \sum_{k=1}^n \left(\frac{x_k - y_k}{s_k}\right)^2 } d(a,b)=k=1n(skxkyk)2

def standard_euclidean_distance():
	x = np.array([1, 2, 3, 4])
	y = np.array([5, 6, 7, 8])
	xy = np.vstack([x, y])
	sk = np.var(xy, axis=0, ddof=1)
	print(f'sk is: {sk}')
	distance = np.sqrt(((x - y) ** 2 / sk).sum())
	print(f'distance is: {distance}')

	distance = pdist(xy, 'seuclidean')
	print(f'distance is: {distance[0]}')

代码输出为:

sk is: [8. 8. 8. 8.]
distance is: 2.8284271247461903
distance is: 2.8284271247461903

3.曼哈顿距离

出租车几何或曼哈顿距离(Manhattan Distance)是由十九世纪的赫尔曼·闵可夫斯基所创词汇 ,是种使用在几何度量空间的几何学用语,用以标明两个点在标准坐标系上的绝对轴距总和。
在直角坐标系中,假设有两点 a = ( x 1 , y 1 ) a=(x_1, y_1) a=(x1,y1), b = ( x 2 , y 2 ) b = (x_2, y_2) b=(x2,y2),则两点的曼哈顿距离为
d ( a , b ) = ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ d(a, b) = |x_1 - x_2| + |y_1 - y_2| d(a,b)=x1x2+y1y2

代码实现如下

def manhattan_distance():
	x = np.array([1, 2, 3, 4])
	y = np.array([5, 6, 7, 8])

	manhattan = np.sum(np.abs(x - y))
	print(f'base on self calculate, manhattan is: {manhattan}')

	xy = np.vstack([x, y])
	manhattan = pdist(xy, 'cityblock')
	print(f'base on pdist, cityblock is: {manhattan[0]}')
base on self calculate, manhattan is: 16
base on pdist, cityblock is: 16.0

4.切比雪夫(Chebyshev)距离

对于两个点,切比雪夫距离定义为各坐标值数值差绝对值中的最大值。如果从向量角度看,就是两个向量各维度差值绝对值的最大值。

对于两个n维向量a, b, a = ( x 1 , x 2 , ⋯   , x n ) , b = ( y 1 , y 2 , ⋯   , y n ) a = (x_1,x_2,\cdots,x_n), b = (y_1,y_2,\cdots,y_n) a=(x1,x2,,xn),b=(y1,y2,,yn),切比雪夫距离为
d ( a , b ) = max ⁡ ( ∣ x 1 − y 1 ∣ , ∣ x 2 − y 2 ∣ , ⋯   , ∣ x n − y n ∣ ) = max ⁡ i ( x i − y i ) d(a, b) = \max(|x_1 - y_1|, |x_2 - y_2|, \cdots, |x_n - y_n|) = \max_i (x_i - y_i) d(a,b)=max(x1y1,x2y2,,xnyn)=imax(xiyi)

上面的表达式等价为
d ( a , b ) = lim ⁡ p → ∞ ( ∑ k = 1 n ∣ x k − y k ∣ p ) 1 / p d(a, b) =\lim_{p \to \infty} \left( { \sum_{k=1}^n |x_k - y_k|^p } \right) ^ {1/p} d(a,b)=plim(k=1nxkykp)1/p

def chebyshev_distance():
	x = np.array([1, 2, 3, 4])
	y = np.array([5, 6, 7, 10])

	distance = np.max(np.abs(x - y))
	print(f'base on self calculate, chebyshev is: {distance}')

	xy = np.vstack([x, y])
	distance = pdist(xy, 'chebyshev')
	print(f'base on pdist, chebyshev is: {distance[0]}')
base on self calculate, chebyshev is: 6
base on pdist, chebyshev is: 6.0

5.闵可夫斯基(Minkowski)距离

对于两个n维向量a, b, a = ( x 1 , x 2 , ⋯   , x n ) , b = ( y 1 , y 2 , ⋯   , y n ) a = (x_1,x_2,\cdots,x_n), b = (y_1,y_2,\cdots,y_n) a=(x1,x2,,xn),b=(y1,y2,,yn),p为一个变量,定义闵可夫斯基距离(闵氏距离)为:

d ( a , b ) = ∑ k = 1 n ∣ x k − y k ∣ p p = ( ∑ k = 1 n ∣ x k − y k ∣ p ) 1 / p d(a, b) =\sqrt [p]{ \sum_{k=1}^n |x_k - y_k|^p } = \left( { \sum_{k=1}^n |x_k - y_k|^p } \right) ^ {1/p} d(a,b)=pk=1nxkykp =(k=1nxkykp)1/p

需要注意的是,闵氏距离不是某一种具体的距离,而是一类距离的定义。
当p=1,此时就是曼哈顿距离。
当p=2,此时就是欧式距离。
p → ∞ p \to \infty p,此时是切比雪夫距离。

def minkowski_distance():
	x = np.array([1, 2, 3, 4])
	y = np.array([5, 6, 7, 8])

	xy = np.vstack([x, y])
	manhattan = pdist(xy, 'minkowski', p=1)
	print(f'when p=1, manhattan result is: {manhattan[0]}')

	euclidean = pdist(xy, 'minkowski', p=2)
	print(f'when p=2, euclidean result is: {euclidean[0]}')
when p=1, manhattan result is: 16.0
when p=2, euclidean result is: 8.0

6.杰卡德(Jaccard)距离

杰卡德相似系数(Jaccard similarity coefficient):是指两个集合A、B中,交集元素在A、B的并集中所占的比例,这个比例叫杰卡德相似系数,可以使用J(A,B)表示。
J ( A , B ) = A ∩ B A ∪ B J(A, B) = \frac{A \cap B}{A \cup B} J(A,B)=ABAB

杰卡德距离(Jaccard Distance)与杰卡德相似系数相反,用两个集合中不同元素的比例来表示两个集合的区分度。
J d ( A , B ) = 1 − J ( A , B ) = A ∪ B − A ∩ B A ∪ B J_d(A, B) = 1 - J(A, B) = \frac{A \cup B - A \cap B}{A \cup B} Jd(A,B)=1J(A,B)=ABABAB

def jaccard_distance():
	x = np.random.random(10) > 0.5
	y = np.random.random(10) > 0.5

	x = np.asarray(x, np.int32)
	y = np.asarray(y, np.int32)

	print("x = ", x)
	print("y = ", y)

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

	# 根据公式求解
	up = np.double(np.bitwise_and((x != y), np.bitwise_or(x != 0, y != 0)).sum())
	down = np.double(np.bitwise_or(x != 0, y != 0).sum())
	dist1 = up / down
	print(f'up is: {up}, down is: {down}')
	print(f"base on pdist, dist1 is: : {dist1}")

	dist2 = pdist(xy, 'jaccard')
x =  [0 0 0 1 0 1 0 1 1 1]
y =  [0 0 1 0 0 0 1 1 0 1]
up is: 5.0, down is: 7.0
base on pdist, dist1 is: : 0.7142857142857143
dist2 is: 0.7142857142857143

注意上面的计算,删除了(0,0)的数据对。

7.汉明(Hamming)距离

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

def hamming_distance():
	x = np.random.random(10) > 0.5
	y = np.random.random(10) > 0.5
	x = np.asarray(x, np.int32)
	y = np.asarray(y, np.int32)

	print(f'x is: {x}')
	print(f'y is: {y}')

	hamming = np.mean(x != y)
	print(f'base on self calculate, hamming is: {hamming}')

	xy = np.vstack([x, y])
	hamming = pdist(xy, 'hamming')
	print(f'base on pdist, hamming is: {hamming[0]}')
x is: [0 0 0 1 0 0 0 1 0 1]
y is: [1 1 1 0 1 1 1 1 1 0]
base on self calculate, hamming is: 0.9
base on pdist, hamming is: 0.9

8.编辑距离(levenshtein distance)

编辑距离是针对二个字符串(例如英文字)的差异程度的量化量测,量测方式是看至少需要多少次的处理才能将一个字符串变成另一个字符串。编辑距离可以用在自然语言处理中,例如拼写检查可以根据一个拼错的字和其他正确的字的编辑距离,判断哪一个(或哪几个)是比较可能的字。DNA也可以视为用A、C、G和T组成的字符串,因此编辑距离也用在生物信息学中,判断二个DNA的类似程度。Unix 下的 diff 及 patch 即是利用编辑距离来进行文本编辑对比的例子。

def levenshtein_distance(s1, s2):
	n, m = len(s1), len(s2)
	distance = [[0 for _ in range(m + 1)] for _ in range(n + 1)]
	for i in range(n + 1):
		distance[i][0] = i
	for j in range(m + 1):
		distance[0][j] = j
	for i in range(1, n + 1):
		for j in range(1, m + 1):
			cost = 0 if s1[i-1] == s2[j-1] else 1
			distance[i][j] = min(
				distance[i - 1][j] + 1,
				distance[i][j - 1] + 1,
				distance[i - 1][j - 1] + cost
			)

	result = distance[n][m]
	print(f'result is: {result}')
	return result


s1, s2 = 'kitten', 'sitting'
levenshtein_distance(s1, s2)
result is: 3

9.余弦距离(cosine distance)

余弦是非常常用的概念。几何中夹角余弦可用来衡量两个向量方向的差异,机器学习中使用这一概念来衡量样本向量之间的差异。相比距离度量,余弦相似度更加注重两个向量在方向上的差异,而非距离或长度上。

def cosine_distance():
	x = np.array([1, 2, 3, 4])
	y = np.array([5, 6, 7, 8])

	cosine = np.dot(x, y) / (np.linalg.norm(x) * np.linalg.norm(y))
	print(f'base on self calculate, cosine is: {cosine}')

	xy = np.vstack([x, y])
	cosine = pdist(xy, 'cosine')
	print(f'base on pdist, cosine is: {1 - cosine[0]}')
base on self calculate, cosine is: 0.9688639316269662
base on pdist, cosine is: 0.9688639316269662

10.皮尔逊相关系数(Pearson correlation coefficient)

皮尔逊相关系数是用来度量两个向量x,y之间的相关性,值位于[-1,1]之间。
两个变量之间的皮尔逊相关系数定义为两个变量的协方差除以它们标准差的乘积:

ρ X , Y = c o v ( X , Y ) σ X σ Y = E [ ( X − μ X ) ( Y − μ Y ) ] σ X σ Y {\displaystyle \rho _{X,Y}={\mathrm {cov} (X,Y) \over \sigma _{X}\sigma _{Y}}={E[(X-\mu _{X})(Y-\mu _{Y})] \over \sigma _{X}\sigma _{Y}}} ρX,Y=σXσYcov(X,Y)=σXσYE[(XμX)(YμY)]

上式定义了总体相关系数,常用希腊小写字母 ρ (rho) 作为代表符号。估算样本的协方差和标准差,可得到样本相关系数(样本皮尔逊系数),常用英文小写字母 r 表示:

r = ∑ i = 1 n ( X i − X ‾ ) ( Y i − Y ‾ ) ∑ i = 1 n ( X i − X ‾ ) 2 ∑ i = 1 n ( Y i − Y ‾ ) 2 r={\frac {\sum \limits _{i=1}^{n}(X_{i}-{\overline {X}})(Y_{i}-{\overline {Y}})}{{\sqrt {\sum \limits _{i=1}^{n}(X_{i}-{\overline {X}})^{2}}} {\sqrt {\sum \limits _{i=1}^{n}(Y_{i}-{\overline {Y}})^{2}}}}} r=i=1n(XiX)2 i=1n(YiY)2 i=1n(XiX)(YiY)

r也可以从样本点的标准分数均值估算,等价的表达式为:

r = 1 n − 1 ∑ i = 1 n ( X i − X ‾ σ X ) ( Y i − Y ‾ σ Y ) r={\frac {1}{n-1}}\sum \limits _{i=1}^{n}\left({\frac {X_{i}-{\overline {X}}}{\sigma _{X}}}\right)\left({\frac {Y_{i}-{\overline {Y}}}{\sigma _{Y}}}\right) r=n11i=1n(σXXiX)(σYYiY)

def pearson_correlation_coefficient():
	x = np.array([1, 2, 3, 4])
	y = np.array([5, 6, 7, 8])

	x_ = x - np.mean(x)
	y_ = y - np.mean(y)

	pearson = np.dot(x_, y_) / (np.linalg.norm(x_) * (np.linalg.norm(y_)))
	print(f'pearson is: {pearson}')

	xy = np.vstack([x, y])
	pearson = np.corrcoef(xy)
	print(f'pearson is: {pearson}')

输出结果为

pearson is: 0.9999999999999998
pearson is: [[1. 1.]
 [1. 1.]]
  • 24
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值