minhash算法

在實際應用的過程中,相似性度量和計算是非常常用的一個方法,例如網頁去重、判斷帖子是否相似、推薦系統衡量物品或者用戶的相似度等等,當數據量大的時候,計算的時間和空間複雜度就會是一個非常重要的問題,例如在判斷相似發帖的時候,我們可以用kmeans來進行聚類,但是資源的消耗是巨大的,所以本文推薦一種方法,minhash+lsh(局部敏感hash),用minhash來降維,用lsh來做近似查詢,本文主要介紹一下minhash。

在介紹minhash之前,先給出相似性的度量方法。

1. 相似性的度量

相似性度量有很多方法,歐氏距離是比較常用的,這裏我們用一下Jaccard相似性係數,公式如下


計算方法很簡單,文檔A和文檔B共有的單詞數除以A和B單詞的集合,例如A={a,b,c,d},B={c,d,e,f},那麼相似性係數就是2/6=0.33。

2. minhash

剛纔我們知道在求相似度的時候我們用到了文檔和單詞。通常情況下,我們都會將文檔和單詞表示成doc-term矩陣的形式,可以看到term具體的是什麼對最後的結果沒有任何影響,所以我索性用行號來代表term,行號跟term是一一對應的,例如

  s1 s2 s3
0 1 0 0
1 0 0 1
2 0 1 0
3 1 0 1
4 0 0 1

第一行中的S1,、S2、S3表示文檔,第一列的01234表示行號,也即單詞,其他部分1表示文檔S中有這個單詞,0表示沒有這個單詞,有了這個集合,我們看一下minhash是怎麼做的

隨機確定一個順序,例如上面的順序是01234,隨機確定一個順序,例如12340,注意這裏是隨機,目的就是不讓最後的結果受人爲的干擾,結果如下

  s1 s2 s3
0 0 0 1
1 0 1 0
2 1 0 1
3 0 0 1
4 1 0 0

我們看到,行號是不變的,行號還是那個行號,變化的是矩陣的內容。找到排在最前面的1代表這個文檔,例如S1排在最前面的1行號爲2,那麼就用2代表文檔S1,同理,用1代表S2,那麼可以計算S1和S2的相似性係數了,1交2除以1並2等於0。後面會給出爲什麼用這種方法是合理的證明。我們暫時先跳過。可以想象一下,用一個單詞來代表一個文檔偶然性會比較大,那麼這個時候我們的想法可能是,可以隨機的產生多次變換,取出多個單詞來進行比較。這個時候問題就來了,在實際應用的過程中,文檔可能有幾百萬,單詞也會有幾萬,對如此龐大的矩陣做變換時間和空間的代價都會比較大,是不是有別的方法呢,答案是肯定的,我們知道運動是相對的,之前是變換矩陣內容不變行號,我們現在不變矩陣,只變換行號,是不是計算量少了非常多。所以問題轉換爲如何產生隨機的行號,我們可以用hash函數來產生行號的順序,兩個函數可以自己定義,最好保證hash後的值均勻,例如x+1mod5,3x+1mod5。我們選用這兩個hash函數來產生行號的順序,看一下我們現在的情況

\ s1 s2 s3 h1(x+1mod5) h2(3x+1mod5)
0 1 0 0 1 1
1 0 0 1 2 4
2 0 1 0 3 2
3 1 0 1 4 0
4 0 0 1 0 3

我們用h1、h2兩個hash函數產生了兩個行號順序,那麼接下來就是關鍵步驟了

例如求文檔s1的值,遍歷s1對應的單詞

從第0行到第四行

1. 第0行爲1,看一下h1計算出來的行號爲1,賦值h1爲1(就是行號),繼續遍歷

2. 第1行爲0,不關心,跳過

3. 第2行爲0,不關心,跳過

4. 第3行爲1, 看一下h1計算出來的行號爲4,4大於此時h1的值,h1的值不變,如果小於h1此時的值,將值付給h1

5. 第4行爲0,不關心,跳過

遍歷完了之後此時h1的值就是1,可以看到,我們其實在做的就是遍歷矩陣中的值,對0的不關心,跳過,對1的,看一下hash函數產生的行號,找到行號最小的值作爲h1輸出的值。同理,h2也一樣,最後得到如下的矩陣

\ s1 s2 s3
h1 1 3 0
h2 1 2 0

這個時候就可以計算s1、s2的相似度了,J=0/3=0

3. 爲什麼minhash的方法是合理的

問題:兩個集合的隨機的一個行排列的minhash值相等的概率和兩個集合的Jaccard相似度相等

證明如下:

兩個集合,A、B,對一行來說,他們的狀態有三種

X:A、B都爲1,即表示A、B集合中都有這個單詞

Y:A、B其中一個爲1,其中一個不爲1,即一個有這個單詞,一個沒有

Z:A、B都爲0,即表示A、B中都沒有這個單詞。

假設有x行爲X,y行爲Y,z行爲z,這是jaccard係數爲x/(x+y)。再看minhash,因爲排列是隨機的,在遇到Y之前遇到X的概率是x/(x+y)。是不是正好等於jaccard係數的值。

4. 如何進行相似查詢比較

通過前面的方法,我們將文檔進行了壓縮,例如使用了30個hash函數,那麼就將一篇文檔壓縮成了30位表示,接下來的問題是如何進行查詢。

一種思路是:建立倒排,term是一個單詞,doclist就是擁有這個單詞的其他文檔。

另一種思路是:不是建立單個單詞的倒排,而是建立多個單詞的聯合倒排,例如

一篇文檔:通過前面的方式用30位進行了表示,將這30爲進行分成m個桶,每桶r個單詞,即m*r=30,這個倒排建立的是:term是r個單詞(或者將這r個單詞求hashcode),doclist就是擁有這r個單詞的文檔。

那麼這裏的問題就是,m、r如何求解,m等於幾好,r等於幾好。

如果兩個文檔相似度爲p,那麼對應位數相似的概率也是p,那麼一個桶裏完全相同的概率是p^r,不相同的概率是1-p^r,那麼m個桶都不相同的概率是(1-p^r)^m,所以至少有一個桶相同的概率是1-(1-p^r)^m,我們可以根據我們想要的概率p去分配m和r。最後建立倒排是這樣的。

桶1——>doc1,doc2,doc3,doc4

桶2——>doc2,doc5,doc9,doc10

索引建立完成了之後,下一步就是檢索,一篇新的文檔,也要經過全面的步驟,得到相應的桶,例如桶1,桶3,那麼接下來就是用桶1查詢,得到跟這篇文檔相似的文檔,爲了保證確實相似,還可以對候選文檔計算一下跟本片文檔的相似度

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章