本文主要介紹餘下的兩種文本類似度的計算方式:html
simhash是google用來處理海量文本去重的算法。simhash就是將一個文檔,最後轉換成一個64位的字節,而後判斷重複只須要判斷他們的各個字節的距離是否是<n(n爲自定義大小,通常取3~5),就能夠判斷兩個文檔是否類似。git
simhash算法分爲5個步驟:分詞、hash、加權、合併、降維,具體過程以下所述:github
分詞
給定一段語句,進行分詞,獲得有效的特徵向量,而後爲每個特徵向量設置1-5等5個級別的權重(若是是給定一個文本,那麼特徵向量能夠是文本中的詞,其權重能夠是這個詞出現的次數)。算法
hash
經過hash函數計算各個特徵向量的hash值,hash值爲二進制數01組成的n-bit簽名。函數
加權
在hash值的基礎上,給全部特徵向量進行加權,即W = Hash weight,且遇到1則hash值和權值正相乘,遇到0則hash值和權值負相乘。google
合併
將上述各個特徵向量的加權結果累加,變成只有一個序列串。編碼
降維
對於n-bit簽名的累加結果,若是大於0則置1,不然置0,從而獲得該語句的simhash值,最後咱們即可以根據不一樣語句simhash的海明距離來判斷它們的類似度。spa
具體的流程圖以下:htm
找到了一個例子來講明具體的步驟:對象
首先對文本內容進行分詞,去掉一些停用詞後,將剩餘的詞語hash編碼,而後對應的每一個詞進行與權重相乘的方式獲得每個詞的新的hash編碼(權重採用的詞的tf-idf的大小做爲權重),而後進行hash對應位置進行合併,最後對合並後的hash進行降維操做。
獲得的每個文檔的simhash均爲等長的hash編碼,因此能夠用漢明距離快速的計算出n值的大小。
例如,兩篇文檔的simhash分別爲:
因此該兩個文本的漢明距離爲3,若n取5,則能夠認爲這兩個文本是類似的。
minhash推薦閱讀博客:
http://www.cnblogs.com/bourne...
文中下面內容將參照該篇博客講解:
問題背景:
給出N個集合,找到類似的集合對,如何實現呢?直觀的方法是比較任意兩個集合。那麼能夠十分精確的找到每一對類似的集合,可是時間複雜度是O(n2)。當N比較小時,好比K級,此算法能夠在接受的時間範圍內完成,可是若是N變大時,比B級,甚至P級,那麼須要的時間是不可以被接受的。
上面的算法雖然效率很低,可是結果會很精確,由於檢查了每一對集合。假如,N個集合中只有少數幾對集合類似,絕大多數集合都不等呢?那麼根據上述算法,絕大多數檢測的結果是兩個結合不類似,能夠說這些檢測「浪費了計算時間」。因此,若是能找到一種算法,將大致上類似的集合聚到一塊兒,縮小比對的範圍,這樣只用檢測較少的集合對,就能夠找到絕大多數類似的集合對,大幅度減小時間開銷。雖然犧牲了一部分精度,可是若是可以將時間大幅度減小,這種算法仍是能夠接受的。接下來的內容講解如何使用Minhash和LSH來實現上述目的,在類似的集合較少的狀況下,能夠在O(n)時間找到大部分類似的集合對。
minhash降維
原始問題的關鍵在於計算時間太長。因此,若是可以找到一種很好的方法將原始集合壓縮成更小的集合,並且又不失去類似性,那麼能夠縮短計算時間。Minhash能夠幫助咱們解決這個問題。舉個例子,S1 = {a,d,e},S2 = {c, e},設全集U = {a,b,c,d,e}。集合能夠以下表示:
表1中,列表示集合,行表示元素,值1表示某個集合具備某個值,0則相反(X,Y,Z的意義後面討論)。Minhash算法大致思路是:採用一種hash函數,將元素的位置均勻打亂,而後將新順序下每一個集合第一個元素做爲該集合的特徵值。好比哈希函數h1(i) = (i + 1) % 5,其中i爲行號。做用於集合S1和S2,獲得以下結果:
這時,Minhash(S1) = e,Minhash(S2) = e。也就是說用元素e表示S1,用元素e表示集合S2。那麼這樣作是否科學呢?進一步,若是Minhash(S1) 等於Minhash(S2),那麼S1是否和S2相似呢?
結論:
P(Minhash(S1) = Minhash(S2)) = Jaccard(S1,S2)
在哈希函數h1均勻分佈的狀況下,集合S1的Minhash值和集合S2的Minhash值相等的機率等於集合S1與集合S2的Jaccard類似度,下面簡單分析一下這個結論。
S1和S2的每一行元素能夠分爲三類:
這裏忽略全部Z類的行,由於此類行對兩個集合是否類似沒有任何貢獻。因爲哈希函數將原始行號均勻分佈到新的行號,這樣能夠認爲在新的行號排列下,任意一行出現X類的狀況的機率爲|X|/(|X|+|Y|)。這裏爲了方便,將任意位置設爲第一個出現X類行的行號。因此P(第一個出現X類) = |X|/(|X|+|Y|) = Jac(S1,S2)。這裏很重要的一點就是要保證哈希函數能夠將數值均勻分佈,儘可能減小衝撞。
通常而言,會找出一系列的哈希函數,好比h個(h << |U|),爲每個集合計算h次Minhash值,而後用h個Minhash值組成一個摘要來表示當前集合(注意Minhash的值的位置須要保持一致)。舉個列子,仍是基於上面的例子,如今又有一個哈希函數h2(i) = (i -1)% 5。那麼獲得以下集合:
因此,如今用摘要表示的原始集合以下:
從表四還能夠獲得一個結論,令X表示Minhash摘要後的集合對應行相等的次數(好比表4,X=1,由於哈希函數h1狀況下,兩個集合的minhash相等,h2不等):
X符合次數爲h,機率爲Jac(S1,S2)的二項分佈。那麼指望E(X) = h Jac(S1,S2) = 2 2 / 3 = 1.33。也就是每2個hash計算Minhash摘要,能夠指望有1.33元素對應相等。
因此,Minhash在壓縮原始集合的狀況下,保證了集合的類似度沒有被破壞。
LSH-局部敏感哈希
如今有了原始集合的摘要,可是仍是沒有解決最初的問題,仍然須要遍歷全部的集合對,,才能全部類似的集合對,複雜度仍然是O(n2)。因此,接下來描述解決這個問題的核心思想LSH。其基本思路是將類似的集合彙集到一塊兒,減少查找範圍,避免比較不類似的集合。仍然是從例子開始,如今有5個集合,計算出對應的Minhash摘要,以下:
上面的集合摘要採用了12個不一樣的hash函數計算出來,而後分紅了B = 4個區間。前面已經分析過,任意兩個集合(S1,S2)對應的Minhash值相等的機率r = Jac(S1,S2)。先分析區間1,在這個區間內,P(集合S1等於集合S2) = r3。因此只要S1和S2的Jaccard類似度越高,在區間1內越有可能完成全一致,反過來也同樣。那麼P(集合S1不等於集合S2) = 1 - r3。如今有4個區間,其餘區間與第一個相同,因此P(4個區間上,集合S1都不等於集合S2) = (1 – r3)4。P(4個區間上,至少有一個區間,集合S1等於集合S2) = 1 - (1 – r3)4。這裏的機率是一個r的函數,形狀猶如一個S型,以下:
若是令區間個數爲B,每一個區間內的行數爲C,那麼上面的公式能夠形式的表示爲:
令r = 0.4,C=3,B = 100。上述公式計算的機率爲0.9986585。這代表兩個Jaccard類似度爲0.4的集合在至少一個區間內衝撞的機率達到了99.9%。根據這一事實,咱們只須要選取合適的B和C,和一個衝撞率很低的hash函數,就能夠將類似的集合至少在一個區間內衝撞,這樣也就達成了本節最開始的目的:將類似的集合放到一塊兒。具體的方法是爲B個區間,準備B個hash表,和區間編號一一對應,而後用hash函數將每一個區間的部分集合映射到對應hash表裏。最後遍歷全部的hash表,將衝撞的集合做爲候選對象進行比較,找出相識的集合對。整個過程是採用O(n)的時間複雜度,由於B和C均是常量。因爲聚到一塊兒的集合相比於總體比較少,因此在這小範圍內互相比較的時間開銷也能夠計算爲常量,那麼整體的計算時間也是O(n)。
http://www.cnblogs.com/bourne...
詳細代碼見github。