在机器学习和人工智能领域,距离(distance)、相似度(similarity)是经常出现的基本概念,关于距离和相似度度量的方法也多种多样,本文将总结一些常用的距离计算方法:
欧氏距离
在二维平面即是两点间的直线距离,是最常用的距离度量的方法之一:
/**
*
* @param p1
* @param p2
* @return Euclidean Distance
*/
def euclidean(p1: Seq[Double], p2: Seq[Double]) = {
require(p1.size == p2.size)
val d = p1.zip(p2)
.map(tp => pow(tp._1 - tp._2, 2))
.sum
sqrt(d)
}
曼哈顿距离
曼哈顿距离(Manhattan Distance)是由十九世纪的赫尔曼·闵可夫斯基所创词汇 ,是种使用在几何度量空间的几何学用语,用以标明两个点在标准坐标系上的绝对轴距总和。
/**
*
* @param p1
* @param p2
* @return Manhattan Distance
*/
def manhattan(p1: Seq[Double], p2: Seq[Double]) = {
require(p1.size == p2.size)
p1.zip(p2).map(tp => abs(tp._1 - tp._2)).sum
}
欧式距离和曼哈顿距离在二维平面空间的图示:
欧式距离与曼哈顿距离
切比雪夫距离
是向量空间中的一种度量,二个点之间的距离定义是其各坐标数值差绝对值的最大值:
/**
*
* @param p1
* @param p2
* @return Chebyshev Distance
*/
def chebyshev(p1: Seq[Double], p2: Seq[Double]) = {
require(p1.size == p2.size)
p1.zip(p2).map(tp => abs(tp._1 - tp._2)).max
}
国际象棋棋盘
闵氏距离
闵氏距离不是一种距离,而是一组距离的定义,上面提到的欧氏距离、曼哈顿距离、切比雪夫距离都是属于闵氏距离。
闵氏距离的定义如下:
/**
*
* @param p1
* @param p2
* @param p
* @return Minkowski Distance
*/
def minkowski(p1: Seq[Double], p2: Seq[Double], p: Int) = {
require(p1.size == p2.size)
val d = p1
.zip(p2)
.map(tp => pow(abs(tp._1 - tp._2), p))
.sum
pow(d, 1 / p)
}
当 p=1 时,就是曼哈顿距离
当 p=2 时,就是欧式距离
当 p趋于无穷 时,就是闵氏距离
杰卡德距离
杰卡德距离(Jaccard Distance) 是用来衡量两个集合差异性的一种指标。
/**
*
* @param p1
* @param p2
* @return Jaccard Distance d(A,B) = 1-J(A,B) 表示Jaccard相似系数
*/
def jaccard(p1: Seq[Any], p2: Seq[Any]) = {
val anb = p1.intersect(p2).distinct
val aub = p1.union(p2).distinct
val jaccardcoefficient = anb.length.toDouble / aub.length
1 - jaccardcoefficient
}
Tanimoto 距离
Tanimoto系数是Jaccard系数的扩展
/**
*
* @param p1
* @param p2
* @return Tanimoto Distance
*/
def tanimoto(p1: Seq[Double], p2: Seq[Double]) = {
require(p1.size == p2.size)
val v1 = new DenseVector(p1.toArray)
val v2 = new DenseVector(p2.toArray)
val a: Double = p1.map(pow(_, 2)).sum
val b: Double = p2.map(pow(_, 2)).sum
val pq = v1.dot(v2)
pq / (a + b - pq)
}
余弦距离
余弦相似度是计算两个向量夹角的余弦值来度量两个向量的相似度,取值在0-1之间,越大则表示两个向量相似度越高:
/**
*
* @param p1
* @param p2
*/
def cos(p1: Seq[Double], p2: Seq[Double]) = {
require(p1.size == p2.size)
val v1 = new DenseVector(p1.toArray)
val v2 = new DenseVector(p2.toArray)
val a = sqrt(p1.map(pow(_, 2)).sum)
val b = sqrt(p2.map(pow(_, 2)).sum)
val ab = v1.t * v2
ab / (a * b)
}
余弦距离图示:
余弦距离 图片来源百度百科
参考资料:
网友评论