文本查重:知識點總結

目錄

整體框架

1. 查詢文本切分策略

2. 文本相似性計算

2.1 計算粒度

2.2 相似性度量算法

2.3 整體相似度的評估

文本相似度

simhash算法及原理簡介

1. 什麼是SimHash

2. SimHash的計算原理

3. 相似度判斷

4. 大規模數據下的海明距離計算

開源代碼實現


整體框架

文本查重需要考慮的問題:

注意:章節序號對查重結果的影響 

具體細節參考: 文本在線查重(Online Copy Detection)的實現

1. 查詢文本切分策略

考慮到如下幾個問題:

(1)百度搜索輸入框中文字符的最大輸入個數爲:38。
(2)通用中文查重標準認爲:連續重複字符數大於等於13屬於抄襲。
(3)句意統一,字符串越長,百度搜索返回的結果往往和查詢結果越匹配。

我們制定如下的查詢文本切分策略:

對於查詢文本,首先以“,;。!?”爲切分符進行切分,得到切分後的字符串集合。
對於切分後的字符串,從前往後儘量組合,在組合後的字符串長度小於38的前提下,組合成的字符串長度越長越好。例如,如果s[i+1]+s[i]>s[i]且s[i+1]+s[i]<38,則將s[i+1]、s[i]兩者組合成新的字符串。

具體實現代碼如下: 

def split_search(query_all):
    query_array = re.split(u"[,;。!?]", query_all.decode('utf-8'))
    if(len(query_array[-1])<5):
        query_array.pop(-1)
    flag = len(query_array)-1
    i = -1
    while (i<flag):
        i += 1
        if(i>flag-1):
            break
        elif(len(query_array[i])<38):
            if(len(query_array[i])+len(query_array[i+1])>38):
                continue
            else:
                query_array[i+1] = query_array[i] + query_array[i+1]
                query_array.pop(i)
                flag -= 1
                i -= 1
        else:
            continue
    
    return query_array

2. 文本相似性計算

2.1 計算粒度

對於查詢文本和搜索結果文本,皆以“,;。!?”爲切分符。
對於切分後的字符串,從前往後組合成長度大於13的字符串,也就是使每一個用於計算的字符串都滿足長度大於13。

def split_content_all(query_all):
    query_array = re.split(r"[,;。!?]", query_all)
    flag = len(query_array)-1
    for i in range(flag):
        if(i>flag-1):
            break
        elif(len(query_array[i])>=13):
            continue
        else:
            query_array[i+1] = query_array[i] + query_array[i+1]
            query_array.pop(i)
            flag -= 1
    return query_array

2.2 相似性度量算法

在介紹具體算法之前,我們先來了解一下有關copy-detection的知識。copy-detection主要用於檢測文件或網頁中相同的內容,判定是否存在拷貝、抄襲等行爲以及程度。在下面的討論中,我們將範圍縮減到只考慮包含ASCII字符的文件,不考慮圖片及視屏等內容。通常情況下,我們認爲用於copy-detection的算法應該滿足以下要求:

1、無視空白符(Whitespace insensitivity)。
在比較文件內容的過程中,我們通常不希望被空格、製表符、標點符號等影響我們判定的結果,因爲它們並不是我們感興趣的內容。在不同的應用下,我們感興趣的內容會有些不同,比如在程序代碼文件中,變量名通常是我們不感興趣的。
2、噪音抑制(Noise suppression)。
主要是指應該排除一些可以接受的拷貝,比如成語、諺語、免責聲明等,這些也不是我們感興趣的。比如在程序代碼文件中,你或許希望排除一些教師給定標程中的內容。
3、位置無關性(Position independence)。
在完全拷貝一份文件後,簡單的將文件內容調換一下位置,仍然屬於抄襲行爲。位置無關性就反映了這麼一種性質,粗粒度的位置調換不會影響最終的判定。更進一步說,從原文件中添加或者刪除一段內容,不應該影響到其他部分的判斷。

基於對問題的分析,我們選取了hash類算法(計算速度快)和字符串直接匹配算法(準確度高)進行了相應實驗,下文將對各類算法的實現和實驗結果進行闡述。

(1)hash類算法

hash 算法的實質就是把數據映射成比較短的固定長度的散列值,從而提高存儲效率或者是計算效率。
具體來說,Hash 算法就是把任意長度的輸入,通過散列算法,變換成固定長度的輸出。該輸出就是散列值。這種轉換是一種壓縮映射,散列值的空間一般遠小於輸入的空間。 但是如果不同的數據通過hash 算法得到了相同的輸出,這個就叫做碰撞,因此不可能從散列值來唯一確定輸入值。
一個優秀的 hash 算法,滿足:

正向快速:給定明文和 hash 算法,在有限時間和有限資源內能計算出 hash 值。
逆向困難:給定(若干) hash 值,在有限時間內很難(基本不可能)逆推出明文。
輸入敏感:原始輸入信息修改一點信息,產生的 hash 值看起來應該都有很大不同。
衝突避免:很難找到兩段內容不同的明文,使得它們的 hash值一致(發生衝突)。即對於任意兩個不同的數據塊,其hash值相同的可能性極小;對於一個給定的數據塊,找到和它hash值相同的數據塊極爲困難。

常見的hash算法包括如下幾種:

  • winnowing算法

        具體原理和實現代碼可參考博客:《【文本相似性計算】winnowing算法》

  • simHash類算法

       具體原理和實現代碼可參考博客:《【文本相似性計算】simHash算法》

  • minHash類算法

      具體原理和實現代碼可參考博客:《【文本相似性計算】minHash和LSH算法》。 

(2)字符串直接匹配算法

常見的字符串直接匹配算法有很多,例如歐幾里得距離、餘弦距離、最長公共子序列、編輯距離(levenshtein距離)、Jaccard相似性係數等。

各類算法的實現代碼參考github:https://github.com/Neo-Luo/TextSimilarity

2.3 整體相似度的評估


具體實現代碼如下:

def cal_total_rate(final_res,query_all):
    score = 0
    for item in final_res['detail']:
        score += final_res['detail'][item]['dist'] * \
           len(final_res['detail'][item]['query_str'])
    final_res['total_rate'] = float(score) / float(len(query_all))
    
    return final_res

文本相似度

計算的處理流程是:

1.對所有文章進行分詞

2.分詞的同時計算各個詞的tf值

3.所有文章分詞完畢後計算idf值

4.生成每篇文章對應的n維向量(n是切分出來的詞數,向量的項就是各個詞的tf-idf值)

5.對文章的向量兩篇兩篇代入餘弦定理公式計算,得出的cos值就是它們之間的相似度了

餘弦相似度:當兩條新聞向量夾角的餘弦等於1時,這兩條新聞完全重複;當夾角的餘弦接近於1時,兩條新聞相似,從而可以歸成一類;夾角的餘弦越小,兩條新聞越不相關

simhash算法及原理簡介

1. 什麼是SimHash

SimHash算法是Google在2007年發表的論文《Detecting Near-Duplicates for Web Crawling》中提到的一種指紋生成算法,被應用在Google搜索引擎網頁去重的工作之中。
簡單的說,SimHash算法主要的工作就是將文本進行降維,生成一個SimHash值,也就是論文中所提及的“指紋”,通過對不同文本的SimHash值進而比較海明距離,從而判斷兩個文本的相似度。
對於文本去重這個問題,常見的解決辦法有餘弦算法、歐式距離、Jaccard相似度、最長公共子串等方法。但是這些方法並不能對海量數據高效的處理。
比如說,在搜索引擎中,會有很多相似的關鍵詞,用戶所需要獲取的內容是相似的,但是搜索的關鍵詞卻是不同的,如“北京好喫的火鍋“和”哪家北京的火鍋好喫“,是兩個可以等價的關鍵詞,然而通過普通的hash計算,會產生兩個相差甚遠的hash串。而通過SimHash計算得到的Hash串會非常的相近,從而可以判斷兩個文本的相似程度。

2. SimHash的計算原理

SimHash算法主要有五個過程:分詞、Hash、加權、合併、降維。

 

        

  • step1:分詞

給定一段語句,進行分詞,得到有效的特徵向量,然後爲每一個特徵向量設置1-5等5個級別的權重(如果是給定一個文本,那麼特徵向量可以是文本中的詞,其權重可以是這個詞出現的次數)。例如給定一段語句:“CSDN博客結構之法算法之道的作者July”,分詞後爲:“CSDN 博客 結構 之 法 算法 之 道 的 作者 July”,然後爲每個特徵向量賦予權值:CSDN(4) 博客(5) 結構(3) 之(1) 法(2) 算法(3) 之(1) 道(2) 的(1) 作者(5) July(5),其中括號裏的數字代表這個單詞在整條語句中的重要程度,數字越大代表越重要。

其中,數字越大,代表特徵詞在句子中的重要性就越高。這樣,我們就得到了一個文本的分詞的詞向量和每個詞向量對應的權重。

  • step2:Hash

通過hash函數計算各個特徵向量的hash值,hash值爲二進制數01組成的n-bit簽名。比如“CSDN”的hash值Hash(CSDN)爲100101,“博客”的hash值Hash(博客)爲“101011”。就這樣,字符串就變成了一系列數字。

  • step3:加權

前面的計算我們已經得到了每個詞向量的Hash串和該詞向量對應的權重,這一步我們計算權重向量W=hash*weight,即遇到1則hash值和權值正相乘,遇到0則hash值和權值負相乘。

例如給“CSDN”的hash值“100101”加權得到:W(CSDN) = 100101 * 4 = 4 -4 -4 4 -4 4,給“博客”的hash值“101011”加權得到:W(博客)=101011 * 5 = 5 -5 5 -5 5 5,其餘特徵向量類似此般操作。

  • step4:合併

對於一個文本,我們計算出了文本分詞之後每一個特徵詞的權重向量,在合併這個階段,我們把文本所有詞向量的權重向量相累加,得到一個新的權重向量,拿前兩個特徵向量舉例,例如“CSDN”的“4 -4 -4 4 -4 4”和“博客”的“5 -5 5 -5 5 5”進行累加,得到“4+5 -4+-5 -4+5 4+-5 -4+5 4+5”,得到“9 -9 1 -1 1”。

  • step5:降維

對於前面合併後得到的文本的權重向量,如果大於0則置1,否則置0,就可以得到該文本的SimHash值。最後我們便可以根據不同語句simhash的海明距離來判斷它們的相似度。例如把上面計算出來的“9 -9 1 -1 1 9”降維(某位大於0記爲1,小於0記爲0),得到的01串爲:“1 0 1 0 1 1”,從而形成它們的simhash簽名。

到此爲止,我們已經計算出了一個文本的SimHash值。那麼,如何判斷兩個文本是否相似呢?我們要用到海明距離。 

3. 相似度判斷

對於兩個文本的SimHash的相似度判斷,我們使用海明距離來計算。什麼是海明距離呢?

簡單的說,Hamming Distance,又稱漢明距離,在信息論中,兩個等長字符串之間的漢明距離是兩個字符串對應位置的不同字符的個數。也就是說,它就是將一個字符串變換成另外一個字符串所需要替換的字符個數。例如:1011101 與 1001001 之間的漢明距離是 2。至於我們常說的字符串編輯距離則是一般形式的漢明距離。

海明距離的求法:異或時,只有在兩個比較的位不同時其結果是1 ,否則結果爲0,兩個二進制“異或”後得到1的個數即爲海明距離的大小。

換言之,現在問題轉換爲:對於64位的SimHash值,我們只要找到海明距離在3以內的所有簽名,即可找出所有相似的短語。

在處理大規模數據的時候,我們一般使用64位的SimHash,正好可以被一個long型存儲。這種時候,海明距離在3以內就可以認爲兩個文本是相似的。

4. 大規模數據下的海明距離計算

如何擴展到海量數據呢?譬如如何在海量的樣本庫中查詢與其海明距離在3以內的記錄呢?

  • 一種方案是,查找待查詢文本的64位simhash code的所有3位以內變化的組合:大約需要四萬多次的查詢。
  • 另一種方案是,預生成庫中所有樣本simhash code的3位變化以內的組合:大約需要佔據4萬多倍的原始空間。

這兩種方案,要麼時間複雜度高,要麼空間複雜度複雜,能否有一種方案可以達到時空複雜度的絕佳平衡呢?答案是肯定的,這時候有一種較好的辦法來均衡計算海明距離的時間複雜度和空間複雜度,具體的計算思想是這樣的:

  • 我們可以把 64 位的二進制simhash簽名均分成4塊,每塊16位。根據鴿巢原理(也稱抽屜原理),如果兩個SimHash相似,即兩個簽名的海明距離在 3 以內,它們必有一塊完全相同。如下圖所示:               
  • 然後把分成的4 塊中的每一個塊分別作爲前16位來進行查找,建倒排索引。

開源代碼實現

1. https://github.com/CuiYongen/DuplicateChecking

 

 

 

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