1. 程式人生 > 實用技巧 >基於jaccard相似度的LSH

基於jaccard相似度的LSH

使用Python通過LSH建立推薦引擎

LSH:一個可以用來處理成百上千行的演算法

前提:

  • Python 基礎
  • Pandas

學完本教程之後,解鎖成就:

  • 通過建立shinglesLSH準備訓練集和測試集
  • LSH挑選引數
  • LSH 建立Minhash
  • 同過LSH 檢索推薦會議論文
  • 通過LSH 建立不同型別的推薦引擎

LSH—Locality-Sensitive Hashing

我們將基於文章的標題以及摘要來推薦會議論文。我們主要有兩種型別的推薦系統:基於內容和協同過濾引擎

  • 基於內容的推薦僅僅依賴於所推薦的條目。關於使用者的資訊一點都沒有
  • 協同過濾使用了使用者的資訊。一般來說資料包含了每個使用者所使用過的條目的喜好。喜歡和不喜歡可以是暗含著的,比如使用者看了一整部電影,也可以是明確的,比如使用者對這部電影豎起大拇指或者給予好評。

大體來說,推薦系統本質上是去尋找條目的相似性。我們可以將相似性視為找到具有較大交集的集合。我們可以收集任何條目,例如文件、電影、網頁...並稱收集到的屬性的集合為shingles,或稱特徵的集合為shingles

shingles

shingles是一個基礎的廣義概念。對於文字,它們可以是字母,一元語法,二元語法。也可以使用類的集合為shinglesshingles 將我們的文件化簡為元素的集合。以此我們可以計算集合之間的相似性。

n元語法(英語:n-gram)指文字中連續出現的n個語詞。

對於我們的會議論文,我們將對文章的標題和摘要使用一元語法。如果我們有一組使用者喜歡哪篇論文的資料,我們甚至可以把使用者當作shingles

來使用。通過這種方式,您可以執行基於專案的協同過濾,在其中搜索由同一使用者正面評價的專案的MinHash

同樣的,你可以反過來想,讓這些專案成為基於使用者的協同過濾的shingles。在這種情況下,您將發現與其他使用者有著相似的正面評價的使用者。

我們取兩個論文的標題並且將他們轉換為1元語法的shingles 的集合。

  • 標題1= "Reinforcement Learning using Augmented Neural networks"
    • shingles =['reinforcement','learning','using','augment','neural','network']
  • 標題2="Playing Atari with Deep Reinforcement Learning"
    • shingles =['playing','atari','with','deep','reinforcement','learning']

現在我們通過視覺的方法觀察兩個集合相交的部分,以此我們可以計算這兩標題的相似性。

為什麼要使用LSH

LSH 可以被視為一種降維的方法。每當我們想從特別大的資料集進行推薦條目時,就會產生一個問題:我們根本不太可能比對完所有條目的相似性。此外,我們可能會為所有條目提供很少量的重疊資料。

要了解為什麼會這樣,我們可以考慮儲存所有會議論文時建立的詞彙矩陣。

傳統上,為了提出建議,我們會為每個文件設定一列,每個詞設定為一行。因為論文的文字內容差異很大,每一列我們都有很多空行。由此具有稀疏性。為了提供建議,我們將會計算那些具有相同之處的每一行的相似性。

paper 1 paper 2 paper 3 ... paper n
word 1 1 0 1 ... 0
word 2 0 0 0 ... 1
word 3 0 1 1 ... 1
...
word n 1 0 1 ... 0

這些問題激發了LSH技術的發展。這種技術可以作為更復雜的推薦引擎的基礎,方法是將行壓縮成“簽名”或整數序列,這樣我們就可以比較論文,而不必比較整個單詞集。

與更傳統的推薦引擎相比,LSH主要加快了推薦程序。 這些模型的伸縮性也更好。 因此,與傳統的推薦引擎相比,在大型資料集上定期對推薦引擎進行再培訓的計算強度要低得多。 在本教程中,我們將通過一個示例向您推薦相似的NIPS會議論文。

商業用例

推薦引擎非常流行。當你使用電腦、手機或平板電腦時,你很可能經常與推薦引擎互動。我們都收到過來自Netflix、Amazon、Facebook、谷歌等網路應用的推薦。這裡有幾個可能是用例的例子:

  • 給顧客推薦產品
  • 預測顧客對產品的評價
  • 根據調查資料建立消費群體
  • 推薦工作流的下一步
  • 在工作流的步驟上提供最佳做法
  • 偵測剽竊行為
  • 查詢近似的文章和作者

LSH 的技術概覽

LSH用基於相似度的簡單概念進行最近鄰搜尋

當兩個條目的集合的並集充分的大時,我們稱這倆具有相似性。

這與集合的Jaccard 相似性完全相同,回顧上圖,我們對相似度的最終衡量標準是1/5,也就是Jaccard 相似度。

NOTE Jaccard similarity is defined as the intersection of two sets divided by the union of the two sets.

注意,其他的用來度量相似性的方法也可以使用,但是在這個教程中我們嚴格使用Jaccard 相似度。LSH 是一種像K-NN,k最近鄰的一種基於鄰域的一種方法。也正如你可以看到的下表一樣,與LSH 相比KNN 的擴充套件性很差。

Model Build Query
KNN O(n2) O(n)
LSH O(n) O(p)

\(n: \mbox{number of items}\)

\(p: \mbox{number of permutations}\)

LSH的強大功能在於,隨著專案數量的增長,它甚至可以使用Forest技術進行次線性擴充套件。 如前所述,目標是找到與查詢集相似的集。

通用的方法是:

  1. 對條目進行雜湊使得相似的條目進入到一個籃子裡具有較高的概率
  2. 將相似性搜尋限制為僅在與查詢項關聯的儲存桶中查詢。

將文字轉換為shingles 的集合

請記住shingle 是一個獨立的元素,它可以是集合的一部分,像字元,一元語法,二元語法。在標準文獻中有一個shingle大小的概念,\(k\) ,當shingle的總數為\(20^k\) 。也就是說當你挑選好shingle 的種類的時候,也已經暗示了shingle 的大小。

舉個例子,我們使用字母表中的字母作為shingle ,所有我們有26種shingle ,這也是shingle 的種數,此時\(k=1,20^k\)近似於是字母表中經常使用的不同字元的數量。

shingling 文件為一元語法時看,我們會發現存在大量可能的單詞,即,我們將k的值設定為較大。下表提供了shingle數量相對於shingle大小k時的情況。

k \(20^k\)
2 400
3 8000
4 16000
5 32000

當涉及到挑選shingle 的時候,你必須有充足不同的shingle ,以使得shingle 出現在給定文件的可能性較低。如果一個shingle 在你的所有集合中出現的過於頻繁,這個shingle 就不可能提供區別於其他集合的資訊。在自然語言處理NPL 中有一個很經典的例項就是”the“,這個出現的太普遍了。大多數的自然語言處理時都會將文件中的the 移除掉,因為其根本不會提供更有用的資訊。類似的,你也不想使用一個出現在所有文件中的屬性當作shingle 。它降低了方法的效率。你在TF-IDF 中也可以看到這樣的想法。出現在太多文件的條目會被打折。

由於您希望任何單個shingle出現在給定文件中的概率都很低,因此我們甚至可以檢視包含雙格、三格或更大的shingle。如果兩個文件中有大量相同的雙字母或三字母格式,則表明這些文件非常相似。

當尋找適當數量的shingle時,請檢視文件中出現的平均字元或標記數。 確保選擇足夠的shingle,以使文件中的shingle比平均數量多得多。

shingle

對於這篇文章我們將會推薦會議文章。我們將快速瀏覽一個與會議論文標題有關的例子:

"Self-Organization of Associative Database and Its Applications"

如果我們使用一元語法作為shingle 時,我們應當移除所有標點符號和停用詞,並且小寫所有字元得到以下結果:

['self','organization','associative','database','application']

注意我們去除了通常的停用詞'like','of','and',and 'its'因為這些詞提供有用的資訊特別少。

Minhash 簽名?特徵?

Minhash的主要目標是用小的signature(這塊翻譯成簽名其實挺合適的)取代大的集合,而且還保留了潛在的相似性度量。

為了對每個集合建立Minhash簽名:

  1. shingle matrix 其行隨機排列。即行12345,變成了行35421,。例如如果"reininforcement" 過去在行1,現在就是在行5。這塊如果看不懂可以看這篇
  2. 對於每一個集合(在我們的例子中是文章的標題),從開始位置起,找到在集合中第一個出現shingle 的位置。第一個shingle 的位置。使用這個shingle number 代表集合。這就是簽名signature
  3. 根據需求重複多次,每次都會將結果附加到集合的簽名中。

我們對三個論文標題進行具體的檢驗。我們已經shingled 標題為一元語法的集合,所以我們可以將其放入進一個矩陣中並且執行以上三步。

\({step\ one}\cal\)

\(\cal{step\ two }\)

\(\cal{step\ three}\)

\(\cal{step \ four}\)

注意:這只是一個簡化的小例子,我們僅僅用到了文章的標題。在下面的實現中我們將會把摘要部分加入進去來實現更精確的推薦。

第一張幻燈片

在左側,我們定義了矩陣,每個標題為一列,我們把三個標題中遇到所有單詞定義為行,如果以一個單詞在標題中出現了,我們在此單詞行對應的標題下記為1,這就是我們雜湊函式的輸入矩陣。

注意,右邊簽名矩陣中的第一個記錄就是我們首先找到1的當前行號。有關更詳細的解釋,請參閱下一張幻燈片。

第二張幻燈片

我們執行第一個實數行全排列。我們注意到,一元語法的單詞有了新的排序。在右側,我們又得到了新的簽名矩陣,我們將在那裡記錄排列的結果。

在每次排列中,我們都會記錄在標題中第一次單詞出現的行數,即,在這次排列中第一次單詞出現所在的行數。在此次排列中標題1標題2第一個一元單詞都出現在行1.因此在標題1標題2下的簽名矩陣第一行都寫著1。對於標題三來說,第一個一元單詞出現在第5行。在簽名矩陣中,標題三那列的第一行就記錄為5.

第三四張幻燈片

本質上呢,這步也是像第二張幻燈片一樣。,唯一的不同點呢就是我們在每次給輸入矩陣重新排列的時候都會將結果記錄並新增到右側的簽名矩陣中。

到目前來說我麼已經完成了三次排列,並且實際上我們已經可以使用簽名矩陣去計算標題之間的相似性。注意我們是如何將shingle 矩陣中的15行壓縮到簽名矩陣中的3行的。

經過MinHash 過程,每篇會議論文都會由MinHash 的簽名所取代,在那裡,矩陣的行數遠小於起始shingle 矩陣。只是因為我們通過行全排列所獲得的簽名。而且需要的排列數,遠少於shingle 數。

現在如果我們考慮在文章標題和摘要所有的單詞,那我們可能以後上百萬個行。通過行排列建立簽名,我們可以有效的將上百萬個行數降低到數百行,而不失其計算相似性的能力

顯然,行排列的次數越多,就會獲得越多的簽名。這就給我們提供了最終的目標,也就是相似的會議論文的簽名也是相似的。事實上,你可以觀察以下結論(其中籤名的相似性為相同的行數比上簽名矩陣所具有的總行數):

\[P(h(\mbox{Set 1}) = h(\mbox{Set 2})) = \mbox{jaccard_sim} (\mbox{Set 1, Set 2})\mbox{,} \\where\ h \ is\ the\ MinHash\ of\ the\ set \]

為了進一步提升效率,在實際使用上我們用隨機雜湊函式代替行的隨機排列。

MinHash 簽名上的LSH

現在。上面的簽名矩陣被分解成b組,每組r行,每一行都分別為hash .對於這個例子來說,我們將組數設定為2,也就是意味著我們將把頭兩行相同的標題視為相似的。 如果組數越大,b越大,另一篇匹配相同排列的論文出現的可能性就越小。

舉個例子。注意上面呈現的矩陣中的第一組,會議論文標題1和會議論文標題2將會進入相同的桶中,因為它們含有相同的組,此時的標題三完全不同。儘管是標題1標題2的簽名有不同,他們依然會進入到同一個桶中,並且在組的規模一定條件下考慮相似性。

Ultimately,最終,組的大小控制著具有給定Jaccard相似性的兩個專案最終出現在同一儲存桶中的可能性。如果組數很大,就會得到很小的集合。舉個例子,\(b=p\) ,\(p\) 是排列的次數,也是簽名矩陣的行數,也會導致對於每一個條目都會建立一個雜湊桶,對於每次排列這是最好的相似。對於我們挑選的組的大小來說,我們真正要尋找的是對於兩類錯誤的容忍性,一種是假陽性(出現在共同的桶中,卻不是相似的文件),還有一種是假陰性(沒有出現在共同的桶中卻是相似的文件)

推薦的檢索

當有一個新的檢索時,我們使用一下流程。

  1. 將要檢索的文字轉換為shingles 或者tokens
  2. shingle set 進行MinHashLSH ,將其對映到一個特殊的桶中
  3. 在要查詢的條目和在桶裡的其他條目之中進行相似度搜索。

在實際上可以通過LSH Forest 演算法進行高效的搜尋來提高效率。想要更多的info,看這個