在机器学习中,会经常与各种距离打交道。于是,在这篇文章中,我们来简单总结一下常见的距离以及其计算方式。

首先定义两个向量a⃗=(x1,x2,…,xn),b⃗=(y1,y2,…,yn)\vec{a}=(x_1,x_2,\ldots,x_n),\vec{b}=(y_1,y_2,\ldots,y_n)a=(x1​,x2​,…,xn​),b=(y1​,y2​,…,yn​),然后计算它们之间的距离。

曼哈顿距离

又称“街区距离”。是向量各维度差值的绝对值之和。
d=∑i=1n∣xi−yi∣ d=\sum_{i=1}^n\vert x_i-y_i\vert d=i=1∑n​∣xi​−yi​∣
曼哈顿距离_360百科

欧氏距离

欧氏距离是大家最为熟悉的距离,早在高中甚至初中学习中就学习过。下面来回顾一下:

普通欧氏距离

普通欧氏距离是两个点在空间中的距离,对应向量就是各个分量差值的平方和再开方。
d=∑i=1n(xi−yi)2 d=\sqrt{\sum_{i=1}^n(x_i-y_i)^2} d=i=1∑n​(xi​−yi​)2​

标准化欧氏距离

为什么需要标准化欧氏距离呢?因为原始的欧氏距离有缺点:

  • 数据各维分量的分布不一样
  • 各个维度之间的尺度不一样

方法:先将各个分量都“标准化”到均值、方差相等。标准化后的值=( 标准化前的值-分量的均值) /分量的标准差
d=∑i=1n(xi−yi)Si2 d=\sqrt{\sum_{i=1}^n\frac{(x_i-y_i)}{S_i}^2} d=i=1∑n​Si​(xi​−yi​)​2​

切比雪夫距离

切比雪夫距离,来源于这样一个问题:国际象棋中的国王,每次可以沿八个方向行动,假设国王从A点到B点,那么国王至少需要移动几步?

对应我们的向量中,问题的答案就是向量各维的差值的最大值。
d=max⁡∣xi−yi∣ d=\max\vert x_i-y_i\vert d=max∣xi​−yi​∣
image-20240318181336470

闵可夫斯基距离

闵可夫斯基距离可能大家不太熟悉。其实它不是一个距离,而是一组距离。它的计算公式为:
d=∑i=1n(xi−yi)pp d=\sqrt[p]{\sum_{i=1}^n (x_i-y_i)^p} d=pi=1∑n​(xi​−yi​)p​
当p取不同的值时,意义也会有所不同了。

  • p=1,为曼哈顿距离
  • p=2,为欧氏距离
  • p=∞\infty∞时,为切比雪夫距离

余弦距离

这个就不是度量向量之间的距离了,它是度量向量方向的差异。
dist(a,b)=1−A⋅B∥A∥⋅∥B∥ dist(a,b)=1-\frac{A\cdot B}{\Vert A\Vert \cdot\Vert B\Vert} dist(a,b)=1−∥A∥⋅∥B∥A⋅B​
它的取值范围[0,2],值越大,说明两个向量方向差异也越大。余弦距离天然实现了归一化,不用考虑各个维度之间的尺度不一样的问题。

字符串距离

在计算机视觉中,是要经常跟字符串打交道的。字符串也有其相应的距离。

汉明距离

汉明距离很常见,它有两种表述:一是两个字符串对应位置的不同字符的个数,二是将其中一个变为另外一个所需要作的最小字符替换次数。

image-20240318185813470

这从编程的角度上来说其实很简单。

例子:

  • 1011111与1001001之间的汉明距离是3

  • happy 与puppy之间的汉明距离是2

int HanMing(const string&a,const string&b){
    //字符串长度不一致时无法计算汉明距离
    if (a.size()!=b.size())
        return -1;
    int ans=0;
    for (int i = 0; i < a.size(); ++i) {
        if (a[i]!=b[i])
            ans++;
    }
    return ans;
}

编辑距离

编辑距离也是一个经典的字符串距离,它指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。

经典算法使用动态规划求解,设字符串A,B,计算它们的编辑距离。

状态转移方程:

image-20240318185537930

下面附上代码实现(C++):

vector<vector<int>>dp;
int Distance(const string&a,const string&b){
    //向量容器初始化(当其中一个字符串为0时的答案)
    dp.assign(a.size()+1,vector<int>(b.size()+1));
    for (int i = 0; i <= a.size(); ++i) {
        dp[i][0]=i;
    }
    for (int i = 0; i <= b.size(); ++i) {
        dp[0][i]=i;
    }
    //状态转移方程(核心部分)
    for (int i = 1; i <= a.size(); ++i) {
        for (int j = 1; j <= b.size(); ++j) {
            if (a[i-1]==b[j-1])
                dp[i][j]=dp[i-1][j-1];
            else
                dp[i][j]= min({dp[i-1][j],dp[i][j-1],dp[i-1][j-1]})+1;
        }
    }
    return dp[a.size()][b.size()];
}
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐