1. 程式人生 > >【機器學習】使用gensim 的 doc2vec 實現文本相似度檢測

【機器學習】使用gensim 的 doc2vec 實現文本相似度檢測

評估 sum ref txt imp uil archive 自然語言 htm

環境

Python3,

gensim,jieba,numpy ,pandas

原理:文章轉成向量,然後在計算兩個向量的余弦值。


Gensim

gensim是一個python的自然語言處理庫,能夠將文檔根據TF-IDF, LDA, LSI 等模型轉化成向量模式,gensim還實現了word2vec功能,以便進行進一步的處理。

具體API看官網:https://radimrehurek.com/gensim


  1. 中文分詞
    中文需要分詞,英文就不需要了,分詞用的 jieba 。
    def segment(doc: str):
    """中文分詞

       Arguments:
           doc {str} -- 輸入文本
       Returns:
           [type] -- [description]
       """
       # 停用詞
       stop_words = pd.read_csv("./data/stopwords_TUH.txt", index_col=False, quoting=3,
                                names=['stopword'],
                                sep="\n",
                                encoding='utf-8')
       stop_words = list(stop_words.stopword)
    # 去掉html標簽數字等
       reg_html = re.compile(r'<[^>]+>', re.S)
       doc = reg_html.sub('', doc)
       doc = re.sub('[0-9]', '', doc)
       doc = re.sub('\s', '', doc)
       word_list = list(jieba.cut(doc))
       out_str = ''
       for word in word_list:
           if word not in stop_words:
               out_str += word
               out_str += ' '
       segments = out_str.split(sep=" ")
    
       return segments
  2. 訓練 Doc2Vec 模型
    模型參數下面說明,先上代碼
    def train():
    """訓練 Doc2Vec 模型
    """

       # 先把所有文檔的路徑存進一個 array中,docLabels:
       data_dir = "./data/corpus_words"
       docLabels = [f for f in listdir(data_dir) if f.endswith('.txt')]
    
       data = []
       for doc in docLabels:
           ws = open(data_dir + "/" + doc, 'r', encoding='UTF-8').read()
           data.append(ws)
    
       print(len(data))
       # 訓練 Doc2Vec,並保存模型:
       sentences = LabeledLineSentence(data, docLabels)
       # 實例化一個模型
       model = gensim.models.Doc2Vec(vector_size=256, window=10, min_count=5,
                                     workers=4, alpha=0.025, min_alpha=0.025, epochs=12)
       model.build_vocab(sentences)
       print("開始訓練...")
       # 訓練模型
       model.train(sentences, total_examples=model.corpus_count, epochs=12)
    
       model.save("./models/doc2vec.model")
       print("model saved")

    保存成功後會有三個文件,分別是:doc2vec.model,doc2vec.model.trainables.syn1neg.npy,doc2vec.model.wv.vectors.npy
    Doc2Vec參數說明:
    · vector_size:是指特征向量的維度,默認為100。大的size需要更多的訓練數據,但是效果會更好.
    · window:表示當前詞與預測詞在一個句子中的最大距離是多少
    · alpha: 是學習速率
    · min_count: 可以對字典做截斷. 詞頻少於min_count次數的單詞會被丟棄掉, 默認值為5
    · workers參數控制訓練的並行數。
    · epochs: 叠代次數,默認為5

  3. 文本轉換成向量
    利用之前保存的模型,把分詞後的分本轉成向量,代碼如下
    def sent2vec(model, words):
    """文本轉換成向量

       Arguments:
           model {[type]} -- Doc2Vec 模型
           words {[type]} -- 分詞後的文本
    
       Returns:
           [type] -- 向量數組
       """
    
       vect_list = []
       for w in words:
           try:
               vect_list.append(model.wv[w])
           except:
               continue
       vect_list = np.array(vect_list)
       vect = vect_list.sum(axis=0)
       return vect / np.sqrt((vect ** 2).sum())
  4. 計算兩個向量余弦值
    余弦相似度,又稱為余弦相似性,是通過計算兩個向量的夾角余弦值來評估他們的相似度。余弦相似度將向量根據坐標值,繪制到向量空間中,如最常見的二維空間。
    余弦值的範圍在[-1,1]之間,值越趨近於1,代表兩個向量的方向越接近;越趨近於-1,他們的方向越相反;接近於0,表示兩個向量近乎於正交。
    最常見的應用就是計算文本相似度。將兩個文本根據他們詞,建立兩個向量,計算這兩個向量的余弦值,就可以知道兩個文本在統計學方法中他們的相似度情況。實踐證明,這是一個非常有效的方法。

公式:
def similarity(a_vect, b_vect):
"""計算兩個向量余弦值

       Arguments:
           a_vect {[type]} -- a 向量
           b_vect {[type]} -- b 向量
       
       Returns:
           [type] -- [description]
       """
   
       dot_val = 0.0
       a_norm = 0.0
       b_norm = 0.0
       cos = None
       for a, b in zip(a_vect, b_vect):
           dot_val += a*b
           a_norm += a**2
           b_norm += b**2
       if a_norm == 0.0 or b_norm == 0.0:
           cos = -1
       else:
           cos = dot_val / ((a_norm*b_norm)**0.5)
   
       return cos
  1. 預測
    def test_model():
    print("load model")
    model = gensim.models.Doc2Vec.load(‘./models/doc2vec.model‘)

       st1 = open('./data/courpus_test/t1.txt', 'r', encoding='UTF-8').read()
       st2 = open('./data/courpus_test/t2.txt', 'r', encoding='UTF-8').read()
       # 分詞
       print("segment")
       st1 = segment(st1)
       st2 = segment(st2)
       # 轉成句子向量
       vect1 = sent2vec(model, st1)
       vect2 = sent2vec(model, st2)
    
       # 查看變量占用空間大小
       import sys
       print(sys.getsizeof(vect1))
       print(sys.getsizeof(vect2))
    
       cos = similarity(vect1, vect2)
       print("相似度:{:.4f}".format(cos))

    看下效果:

完全相同的文章
技術分享圖片

不相同的文章
技術分享圖片

數據太大,沒有上傳,自己網上找找應該有很多。

完整代碼:https://github.com/jarvisqi/nlp_learning/blob/master/gensim/doc2vector.py

參考:

  • https://radimrehurek.com/gensim
  • https://spaces.ac.cn/archives/4304

【機器學習】使用gensim 的 doc2vec 實現文本相似度檢測