機器學習距離公式總結

做者:daniel-D 出處:http://www.cnblogs.com/daniel-D/php

在機器學習和數據挖掘中,咱們常常須要知道個體間差別的大小,進而評價個體的類似性和類別。最多見的是數據分析中的相關分析,數據挖掘中的分類和聚類算法,如 K 最近鄰(KNN)和 K 均值(K-Means)等等。根據數據特性的不一樣,能夠採用不一樣的度量方法。通常而言,定義一個距離函數 d(x,y), 須要知足下面幾個準則:html

1) d(x,x) = 0                    // 到本身的距離爲0
2) d(x,y) >= 0                  // 距離非負
3) d(x,y) = d(y,x)                   // 對稱性: 若是 A 到 B 距離是 a,那麼 B 到 A 的距離也應該是 a
4) d(x,k)+ d(k,y) >= d(x,y)    // 三角形法則: (兩邊之和大於第三邊)python

這篇博客主要介紹機器學習和數據挖掘中一些常見的距離公式,包括:算法

  1. 閔可夫斯基距離
  2. 歐幾里得距離
  3. 曼哈頓距離
  4. 切比雪夫距離
  5. 馬氏距離
  6. 餘弦類似度
  7. 皮爾遜相關係數
  8. 漢明距離
  9. 傑卡德類似係數
  10. 編輯距離
  11. DTW 距離
  12. KL 散度

 

1. 閔可夫斯基距離

閔可夫斯基距離(Minkowski distance)是衡量數值點之間距離的一種很是常見的方法,假設數值點 P 和 Q 座標以下:app

那麼,閔可夫斯基距離定義爲:dom

該距離最經常使用的 p 是 2 和 1, 前者是歐幾里得距離(Euclidean distance),後者是曼哈頓距離(Manhattan distance)。假設在曼哈頓街區乘坐出租車從 P 點到 Q 點,白色表示高樓大廈,灰色表示街道:機器學習

綠色的斜線表示歐幾里得距離,在現實中是不可能的。其餘三條折線表示了曼哈頓距離,這三條折線的長度是相等的。ide

當 p 趨近於無窮大時,閔可夫斯基距離轉化成切比雪夫距離(Chebyshev distance):函數

咱們知道平面上到原點歐幾里得距離(p = 2)爲 1 的點所組成的形狀是一個圓,當 p 取其餘數值的時候呢?post

注意,當 p < 1 時,閔可夫斯基距離再也不符合三角形法則,舉個例子:當 p < 1, (0,0) 到 (1,1) 的距離等於 (1+1)^{1/p} > 2, 而 (0,1) 到這兩個點的距離都是 1。

閔可夫斯基距離比較直觀,可是它與數據的分佈無關,具備必定的侷限性,若是 x 方向的幅值遠遠大於 y 方向的值,這個距離公式就會過分放大 x 維度的做用。因此,在計算距離以前,咱們可能還須要對數據進行 z-transform 處理,即減去均值,除以標準差:

 : 該維度上的均值
 : 該維度上的標準差

能夠看到,上述處理開始體現數據的統計特性了。這種方法在假設數據各個維度不相關的狀況下利用數據分佈的特性計算出不一樣的距離。若是維度相互之間數據相關(例如:身高較高的信息頗有可能會帶來體重較重的信息,由於二者是有關聯的),這時候就要用到馬氏距離(Mahalanobis distance)了。

 

2. 馬氏距離

考慮下面這張圖,橢圓表示等高線,從歐幾里得的距離來算,綠黑距離大於紅黑距離,可是從馬氏距離,結果剛好相反:

馬氏距離其實是利用 Cholesky transformation 來消除不一樣維度之間的相關性和尺度不一樣的性質。假設樣本點(列向量)之間的協方差對稱矩陣是  , 經過 Cholesky Decomposition(其實是對稱矩陣 LU 分解的一種特殊形式,可參考以前的博客)能夠轉化爲下三角矩陣和上三角矩陣的乘積:  。消除不一樣維度之間的相關性和尺度不一樣,只須要對樣本點 x 作以下處理: 。處理以後的歐幾里得距離就是原樣本的馬氏距離:爲了書寫方便,這裏求馬氏距離的平方):

下圖藍色表示原樣本點的分佈,兩顆紅星座標分別是(3, 3),(2, -2):

因爲 x, y 方向的尺度不一樣,不能單純用歐幾里得的方法測量它們到原點的距離。而且,因爲 x 和 y 是相關的(大體能夠看出斜向右上),也不能簡單地在 x 和 y 方向上分別減去均值,除以標準差。最恰當的方法是對原始數據進行 Cholesky 變換,即求馬氏距離(能夠看到,右邊的紅星離原點較近):

將上面兩個圖的繪製代碼和求馬氏距離的代碼貼在這裏,以備之後查閱:

# -*- coding=utf-8 -*-

# code related at: http://www.cnblogs.com/daniel-D/

import numpy as np
import pylab as pl
import scipy.spatial.distance as dist


def plotSamples(x, y, z=None):

    stars = np.matrix([[3., -2., 0.], [3., 2., 0.]])
    if z is not None:
        x, y = z * np.matrix([x, y])
        stars = z * stars

    pl.scatter(x, y, s=10)    # 畫 gaussian 隨機點
    pl.scatter(np.array(stars[0]), np.array(stars[1]), s=200, marker='*', color='r')  # 畫三個指定點
    pl.axhline(linewidth=2, color='g') # 畫 x 軸
    pl.axvline(linewidth=2, color='g')  # 畫 y 軸

    pl.axis('equal')
    pl.axis([-5, 5, -5, 5])
    pl.show()


# 產生高斯分佈的隨機點
mean = [0, 0]      # 平均值
cov = [[2, 1], [1, 2]]   # 協方差
x, y = np.random.multivariate_normal(mean, cov, 1000).T
plotSamples(x, y)

covMat = np.matrix(np.cov(x, y))    # 求 x 與 y 的協方差矩陣
Z = np.linalg.cholesky(covMat).I  # 仿射矩陣
plotSamples(x, y, Z)

# 求馬氏距離 
print '\n到原點的馬氏距離分別是:'
print dist.mahalanobis([0,0], [3,3], covMat.I), dist.mahalanobis([0,0], [-2,2], covMat.I)

# 求變換後的歐幾里得距離
dots = (Z * np.matrix([[3, -2, 0], [3, 2, 0]])).T
print '\n變換後到原點的歐幾里得距離分別是:'
print dist.minkowski([0, 0], np.array(dots[0]), 2), dist.minkowski([0, 0], np.array(dots[1]), 2)


 

馬氏距離的變換和 PCA 分解的白化處理很有殊途同歸之妙,不一樣之處在於:就二維來看,PCA 是將數據主成分旋轉到 x 軸(正交矩陣的酉變換),再在尺度上縮放(對角矩陣),實現尺度相同。而馬氏距離的 L逆矩陣是一個下三角,先在 x 和 y 方向進行縮放,再在 y 方向進行錯切(想象矩形變平行四邊形),整體來講是一個沒有旋轉的仿射變換。

 

3. 向量內積

向量內積是線性代數裏最爲常見的計算,實際上它仍是一種有效而且直觀的類似性測量手段。向量內積的定義以下:

直觀的解釋是:若是 x 高的地方 y 也比較高, x 低的地方 y 也比較低,那麼總體的內積是偏大的,也就是說 x 和 y 是類似的。舉個例子,在一段長的序列信號 A 中尋找哪一段與短序列信號 a 最匹配,只須要將 a 從 A 信號開頭逐個向後平移,每次平移作一次內積,內積最大的類似度最大。信號處理中 DFT 和 DCT 也是基於這種內積運算計算出不一樣頻域內的信號組分(DFT 和 DCT 是正交標準基,也能夠看作投影)。向量和信號都是離散值,若是是連續的函數值,好比求區間[-1, 1] 兩個函數之間的類似度,一樣也能夠獲得(係數)組分,這種方法能夠應用於多項式逼近連續函數,也能夠用到連續函數逼近離散樣本點(最小二乘問題,OLS coefficients)中,扯得有點遠了- -!。

向量內積的結果是沒有界限的,一種解決辦法是除以長度以後再求內積,這就是應用十分普遍的餘弦類似度(Cosine similarity):

餘弦類似度與向量的幅值無關,只與向量的方向相關,在文檔類似度(TF-IDF)和圖片類似性(histogram)計算上都有它的身影。須要注意一點的是,餘弦類似度受到向量的平移影響,上式若是將 x 平移到 x+1, 餘弦值就會改變。怎樣才能實現平移不變性?這就是下面要說的皮爾遜相關係數(Pearson correlation),有時候也直接叫相關係數:

皮爾遜相關係數具備平移不變性和尺度不變性,計算出了兩個向量(維度)的相關性。不過,通常咱們在談論相關係數的時候,將 x 與 y 對應位置的兩個數值看做一個樣本點,皮爾遜係數用來表示這些樣本點分佈的相關性。

因爲皮爾遜係數具備的良好性質,在各個領域都應用普遍,例如,在推薦系統根據爲某一用戶查找喜愛類似的用戶,進而提供推薦,優勢是能夠不受每一個用戶評分標準不一樣和觀看影片數量不同的影響。

 

4. 分類數據點間的距離

漢明距離(Hamming distance)是指,兩個等長字符串s1與s2之間的漢明距離定義爲將其中一個變爲另一個所須要做的最小替換次數。舉個維基百科上的例子:

還能夠用簡單的匹配係數來表示兩點之間的類似度——匹配字符數/總字符數。

在一些狀況下,某些特定的值相等並不能表明什麼。舉個例子,用 1 表示用戶看過該電影,用 0 表示用戶沒有看過,那麼用戶看電影的的信息就可用 0,1 表示成一個序列。考慮到電影基數很是龐大,用戶看過的電影只佔其中很是小的一部分,若是兩個用戶都沒有看過某一部電影(兩個都是 0),並不能說明二者類似。反而言之,若是兩個用戶都看過某一部電影(序列中都是 1),則說明用戶有很大的類似度。在這個例子中,序列中等於 1 所佔的權重應該遠遠大於 0 的權重,這就引出下面要說的傑卡德類似係數(Jaccard similarity)。

在上面的例子中,用 M11 表示兩個用戶都看過的電影數目,M10 表示用戶 A 看過,用戶 B 沒看過的電影數目,M01 表示用戶 A 沒看過,用戶 B 看過的電影數目,M00 表示兩個用戶都沒有看過的電影數目。Jaccard 類似性係數能夠表示爲:

Jaccard similarity 還能夠用集合的公式來表達,這裏就很少說了。

若是分類數值點是用樹形結構來表示的,它們的類似性能夠用相同路徑的長度來表示,好比,「/product/spot/ballgame/basketball」 離「product/spot/ballgame/soccer/shoes」 的距離小於到 "/product/luxury/handbags" 的距離,覺得前者相同父節點路徑更長。

 

5. 序列之間的距離

上一小節咱們知道,漢明距離能夠度量兩個長度相同的字符串之間的類似度,若是要比較兩個不一樣長度的字符串,不只要進行替換,並且要進行插入與刪除的運算,在這種場合下,一般使用更加複雜的編輯距離(Edit distance, Levenshtein distance)等算法。編輯距離是指兩個字串之間,由一個轉成另外一個所需的最少編輯操做次數。許可的編輯操做包括將一個字符替換成另外一個字符,插入一個字符,刪除一個字符。編輯距離求的是最少編輯次數,這是一個動態規劃的問題,有興趣的同窗能夠本身研究研究。

時間序列是序列之間距離的另一個例子。DTW 距離(Dynamic Time Warp)是序列信號在時間或者速度上不匹配的時候一種衡量類似度的方法。神馬意思?舉個例子,兩份本來同樣聲音樣本A、B都說了「你好」,A在時間上發生了扭曲,「你」這個音延長了幾秒。最後A:「你~~~好」,B:「你好」。DTW正是這樣一種能夠用來匹配A、B之間的最短距離的算法。

DTW 距離在保持信號前後順序的限制下對時間信號進行「膨脹」或者「收縮」,找到最優的匹配,與編輯距離類似,這其實也是一個動態規劃的問題:

實現代碼(轉自 McKelvin's Blog ):

 

#!/usr/bin/python2
# -*- coding:UTF-8 -*-
# code related at: http://blog.mckelv.in/articles/1453.html
 
import sys
 
distance = lambda a,b : 0 if a==b else 1
 
def dtw(sa,sb):
    '''
    >>>dtw(u"幹啦今今今今今每天氣氣氣氣氣好好好好啊啊啊", u"今每天氣好好啊")
    2
    '''
    MAX_COST = 1<<32
    #初始化一個len(sb) 行(i),len(sa)列(j)的二維矩陣
    len_sa = len(sa)
    len_sb = len(sb)
    # BUG:這樣是錯誤的(淺拷貝): dtw_array = [[MAX_COST]*len(sa)]*len(sb)
    dtw_array = [[MAX_COST for i in range(len_sa)] for j in range(len_sb)]
    dtw_array[0][0] = distance(sa[0],sb[0])
    for i in xrange(0, len_sb):
        for j in xrange(0, len_sa):
            if i+j==0:
                continue
            nb = []
            if i > 0: nb.append(dtw_array[i-1][j])
            if j > 0: nb.append(dtw_array[i][j-1])
            if i > 0 and j > 0: nb.append(dtw_array[i-1][j-1])
            min_route = min(nb)
            cost = distance(sa[j],sb[i])
            dtw_array[i][j] = cost + min_route
    return dtw_array[len_sb-1][len_sa-1]
 
 
def main(argv):
    s1 = u'幹啦今今今今今每天氣氣氣氣氣好好好好啊啊啊'
    s2 = u'今每天氣好好啊'
    d = dtw(s1, s2)
    print d
    return 0
 
if __name__ == '__main__':
    sys.exit(main(sys.argv))


 

 

6. 機率分佈之間的距離

前面咱們談論的都是兩個數值點之間的距離,實際上兩個機率分佈之間的距離是能夠測量的。在統計學裏面常常須要測量兩組樣本分佈之間的距離,進而判斷出它們是否出自同一個 population,常見的方法有卡方檢驗(Chi-Square)和 KL 散度( KL-Divergence),下面說一說 KL 散度吧。

先從信息熵提及,假設一篇文章的標題叫作「黑洞到底吃什麼」,包含詞語分別是 {黑洞, 到底, 吃什麼}, 咱們如今要根據一個詞語推測這篇文章的類別。哪一個詞語給予咱們的信息最多?很容易就知道是「黑洞」,由於「黑洞」這個詞語在全部的文檔中出現的機率過低啦,一旦出現,就代表這篇文章極可能是在講科普知識。而其餘兩個詞語「到底」和「吃什麼」出現的機率很高,給予咱們的信息反而越少。如何用一個函數 h(x) 表示詞語給予的信息量呢?第一,確定是與 p(x) 相關,而且是負相關。第二,假設 x 和 y 是獨立的(黑洞和宇宙不相互獨立,談到黑洞必然會說宇宙),即 p(x,y) = p(x)p(y), 那麼得到的信息也是疊加的,即 h(x, y) = h(x) + h(y)。知足這兩個條件的函數確定是負對數形式:

對假設一個發送者要將隨機變量 X 產生的一長串隨機值傳送給接收者, 接受者得到的平均信息量就是求它的數學指望:

這就是熵的概念。另一個重要特色是,熵的大小與字符平均最短編碼長度是同樣的(shannon)。設有一個未知的分佈 p(x), 而 q(x) 是咱們所得到的一個對 p(x) 的近似,按照 q(x) 對該隨機變量的各個值進行編碼,平均長度比按照真實分佈的 p(x) 進行編碼要額外長一些,多出來的長度這就是 KL 散度(之因此不說距離,是由於不知足對稱性和三角形法則),即:

KL 散度又叫相對熵(relative entropy)。瞭解機器學習的童鞋應該都知道,在 Softmax 迴歸(或者 Logistic 迴歸),最後的輸出節點上的值表示這個樣本分到該類的機率,這就是一個機率分佈。對於一個帶有標籤的樣本,咱們指望的機率分佈是:分到標籤類的機率是 1, 其餘類機率是 0。可是理想很豐滿,現實很骨感,咱們不可能獲得完美的機率輸出,能作的就是儘可能減少總樣本的 KL 散度之和(目標函數)。這就是 Softmax 迴歸或者 Logistic 迴歸中 Cost function 的優化過程啦。(PS:由於機率和爲 1,通常的 logistic 二分類的圖只畫了一個輸出節點,隱藏了另一個)

 


 

待補充的方法:

卡方檢驗 Chi-Square

衡量 categorical attributes 相關性的 mutual information

Spearman's rank coefficient

Earth Mover's Distance

SimRank 迭代算法等。

 

參考資料:

  1. 距離和類似性度量
  2. Machine Learning: Measuring Similarity and Distance
  3. What is Mahalanobis distance?
  4. Cosine similarity, Pearson correlation, and OLS coefficients
  5. 機器學習中的類似性度量
  6. 動態時間歸整 | DTW | Dynamic Time Warping
相關文章
相關標籤/搜索