1. 程式人生 > >【轉載】機器學習計算距離和相似度的方法

【轉載】機器學習計算距離和相似度的方法

3. 向量內積

向量內積是線性代數裡最為常見的計算,實際上它還是一種有效並且直觀的相似性測量手段。向量內積的定義如下:

直觀的解釋是:如果 x 高的地方 y 也比較高, x 低的地方 y 也比較低,那麼整體的內積是偏大的,也就是說 x 和 y 是相似的。舉個例子,在一段長的序列訊號 A 中尋找哪一段與短序列訊號 a 最匹配,只需要將 a 從 A 訊號開頭逐個向後平移,每次平移做一次內積,內積最大的相似度最大。訊號處理中 DFT 和 DCT 也是基於這種內積運算計算出不同頻域內的訊號組分(DFT 和 DCT 是正交標準基,也可以看做投影)。向量和訊號都是離散值,如果是連續的函式值,比如求區間[-1, 1]

 兩個函式之間的相似度,同樣也可以得到(係數)組分,這種方法可以應用於多項式逼近連續函式,也可以用到連續函式逼近離散樣本點(最小二乘問題,)中,扯得有點遠了- -!。

向量內積的結果是沒有界限的,一種解決辦法是除以長度之後再求內積,這就是應用十分廣泛的餘弦相似度(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 距離在保持訊號先後順序的限制下對時間訊號進行“膨脹”或者“收縮”,找到最優的匹配,與編輯距離相似,這其實也是一個動態規劃的問題:

  1. <span style="background-color: rgb(255, 255, 255);">#!/usr/bin/python2  
  2. # -*- coding:UTF-8 -*-  
  3. # code related at: http://blog.mckelv.in/articles/1453.html
  4. import sys  
  5. distance = lambda a,b : 0if a==b else1
  6. def dtw(sa,sb):  
  7.     '''  
  8.     >>>dtw(u"幹啦今今今今今天天氣氣氣氣氣好好好好啊啊啊", u"今天天氣好好啊")  
  9.     2
  10.     '''  
  11.     MAX_COST = 1<<32
  12.     #初始化一個len(sb) 行(i),len(sa)列(j)的二維矩陣  
  13.     len_sa = len(sa)  
  14.     len_sb = len(sb)  
  15.     # BUG:這樣是錯誤的(淺拷貝): dtw_array = [[MAX_COST]*len(sa)]*len(sb)  
  16.     dtw_array = [[MAX_COST for i in range(len_sa)] for j in range(len_sb)]  
  17.     dtw_array[0][0] = distance(sa[0],sb[0])  
  18.     for i in xrange(0, len_sb):  
  19.         for j in xrange(0, len_sa):  
  20.             if i+j==0:  
  21.                 continue
  22.             nb = []  
  23.             if i > 0: nb.append(dtw_array[i-1][j])  
  24.             if j > 0: nb.append(dtw_array[i][j-1])  
  25.             if i > 0 and j > 0: nb.append(dtw_array[i-1][j-1])  
  26.             min_route = min(nb)  
  27.             cost = distance(sa[j],sb[i])  
  28.             dtw_array[i][j] = cost + min_route  
  29.     return dtw_array[len_sb-1][len_sa-1]  
  30. def main(argv):  
  31.     s1 = u'幹啦今今今今今天天氣氣氣氣氣好好好好啊啊啊'
  32.     s2 = u'今天天氣好好啊'
  33.     d = dtw(s1, s2)  
  34.     print d  
  35.     return0
  36. if __name__ == '__main__':  
  37.     sys.exit(main(sys.argv))</span>  


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 二分類的圖只畫了一個輸出節點,隱藏了另外一個)