1. 程式人生 > >gensim基礎學習(一)

gensim基礎學習(一)

       最近參加了個長文字分類的比賽,然後開始使用gensim,一個很強大的NLP神器,用於從原始的非結構化的文字中,無監督地學習到文字隱層的主題向量表達,在此記錄一下使用心得。

目錄

基本概念

基本概念

  • 語料(Corpus):一組原始文字的集合,用於無監督地訓練文字主題的隱層結構。在Gensim中,Corpus通常是一個可迭代的物件,每一次迭代返回一個可用於表達文字物件的稀疏向量。
  • 向量(Vector):由一組文字特徵構成的列表。是一段文字在Gensim中的內部表達。
  • 稀疏向量(Sparse Vector):通常,我們可以略去向量中多餘的0元素。此時,向量中的每一個元素是一個(key, value)的tuple。key表示在字典中的索引值,value表示出現的次數。
  • 模型(Model):是一個抽象的術語。定義了兩個向量空間的變換(即從文字的一種向量表達變換為另一種向量表達)

1.語料的處理

       對語料進行切分、去除停用詞等基本處理,得到每一篇文件的特徵列表。比如下面的列表

postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
               ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
               ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him', 'my'],
               ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
               ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
               ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]

2.生成詞典和向量轉化

 from gensim import corpora

 dictionary = corpora.Dictionary(texts)

 print(dictionary)

     顯示如下:

     Dictionary(32 unique tokens: ['dog', 'flea', 'has', 'help', 'my']...)

     其中字典還有很多實用的方法

print(dictionary.token2id)

# id2word print(dictionary.token2id)

# word2id print(dictionary.dfs) # 詞頻

     結果如下,詞頻的key值是字典中單詞的索引值:

{'dog': 0, 'flea': 1, 'has': 2, 'help': 3, 'my': 4, 'please': 5, 'problems': 6, 'him': 7, 'maybe': 8, 'not': 9, 'park': 10, 'stupid': 11, 'take': 12, 'to': 13, 'I': 14, 'cute': 15, 'dalmation': 16, 'is': 17, 'love': 18, 'so': 19, 'garbage': 20, 'posting': 21, 'stop': 22, 'worthless': 23, 'ate': 24, 'how': 25, 'licks': 26, 'mr': 27, 'steak': 28, 'buying': 29, 'food': 30, 'quit': 31} {4: 3, 0: 3, 2: 1, 1: 1, 6: 1, 3: 1, 5: 1, 8: 1, 9: 1, 12: 1, 7: 3, 13: 2, 10: 1, 11: 3, 16: 1, 17: 1, 19: 1, 15: 1, 14: 1, 18: 1, 22: 2, 21: 1, 23: 2, 20: 1, 27: 1, 26: 1, 24: 1, 28: 1, 25: 1, 31: 1, 29: 1, 30: 1}  

 其他方法:

dictionary.filter_n_most_frequent(N) 過濾掉出現頻率最高的N個單詞

dictionary.filter_extremes(no_below=5, no_above=0.5, keep_n=100000)

    1.去掉出現次數低於no_below的

    2.去掉出現次數高於no_above的。注意這個小數指的是百分數

    3.在1和2的基礎上,保留出現頻率前keep_n的單詞

dictionary.filter_tokens(bad_ids=None, good_ids=None)

有兩種用法,一種是去掉bad_id對應的詞,另一種是保留good_id對應的詞而去掉其他詞。

dictionary.compacity() 在執行完前面的過濾操作以後,可能會造成單詞的序號之間有空隙,這時就可以使用該函式來對詞典來進行重新排序,去掉這些空隙。

dictionary.merge_with(other)和其他字典合併

字典持久化和載入

dictionary.save("data/mydict.dic")

dictionary = corpora.Dictionary.load('data/mydict.dic')

將文字特徵的原始表達轉為詞袋模型對應的稀疏向量的表達。

corpus = [dictionary.doc2bow(text) for text in postingList] print(corpus)

 顯示如下,其中(9,1)表示在字典中索引為9對應的單詞,出現了1次:

[[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1)], [(0, 1), (7, 1), (8, 1), (9, 1), (10, 1), (11, 1), (12, 1), (13, 1)], [(4, 2), (7, 1), (14, 1), (15, 1), (16, 1), (17, 1), (18, 1), (19, 1)], [(11, 1), (20, 1), (21, 1), (22, 1), (23, 1)], [(4, 1), (7, 1), (13, 1), (22, 1), (24, 1), (25, 1), (26, 1), (27, 1), (28, 1)], [(0, 1), (11, 1), (23, 1), (29, 1), (30, 1), (31, 1)]]

 語料的持久化和載入

corpora.MmCorpus.serialize("data/corpus.mm", corpus)  

corpus = corpora.MmCorpus("data/corpus.mm")

 3.主題向量的轉化

       (1)首先是模型物件的初始化。通常,Gensim模型都接受一段訓練語料(注意在Gensim中,語料對應著一個稀疏向量的迭代器)作為初始化的引數。

       (2)利用初始化的模型將語料轉化為物件的向量

1)TFIDF(詞頻逆文件頻率)

          from gensim import models

          tfidf = models.TfidfModel(corpus)

          tfidf.save("./model.tfidf")

          tfidf = models.TfidfModel.load("./model.tfidf")

2)LSI(潛在語義索引)

   將詞袋模型或TFIDF空間對映到低維度的潛在空間,推薦200-500為金標準,在達觀資料的長文字分類中,嘗試350的維度分數得分優於其他維度。LSI可以進行增量訓練,只要有新文件可以一直輸入模型當中,通過add_document方法。如果python報memoryerror,那就是記憶體不夠了,需要降低維度。

          lsi_model = models.LsiModel(corpus, id2word=dictionary, num_topics=2)

         #這是指的潛在主題(topic)的數目,也等於轉成lsi模型以後每個文件對應的向量長度。轉化以後的向量在各項的值,即為該文件   在該潛在主題的權重。

          documents = lsi_model[corpus]

          lsi_model.save("data/model1.lsi")

          lsi_model = models.LsiModel.load("data/model2.lsi")

3)LDA(隱含狄利克雷分配)

       LDA是LSA的概率擴充套件,也是向低緯度轉化的方式

          lda_model = LdaModel(corpus=corpus, id2word=dictionary, num_topics=100)

          documents = lda_model[corpus]

          lda_model .save("data/model1.lsi")

          lda_model = models.LsiModel.load("data/model2.lsi")

4)RP(隨即對映)

 目的在於減小空維度,通過隨機性,近似的到文件之間的TFIDF距離,不過對於大資料量確實很慢,反正10萬篇文件的資料我的小電腦是受不了

model=rpmodel.RpModel(corpus, num_topics=2)

 4.相似度匹配

  在得到文章對應的主題向量以後,就可以進行相似性匹配,我第一次是用在了長文字分類上,將多個文件遍歷進行匹配,然後排序選擇相似度最大的文章,取其在訓練集中對應的分類編號,作為測試文件的類別。在單純使用LSI向量,不加入TFIDF的情況下,準確率不高。

   如果單純將corpus轉化為LSI向量,主需要將測試文章用LSI模型轉化一次:

   lsi_model = models.LsiModel(corpus, id2word=dictionary, num_topics=2)

  documents = lsi_model[corpus]  #訓練資料轉化為LSI向量

  query_vec = lsi_model[query]   #測試資料轉化為LSI向量

  相似度匹配:

index = similarities.MatrixSimilarity(documents)

#網上說這個會佔用大量的記憶體,如果記憶體不足可以改用similarities.Similarity

sims = index[query_vec]

predclass = listClasses[np.where(sims == np.max(sims))[0][0]]   #取對應訓練資料的分類

 相似度矩陣的持久化(會生成多個檔案,千萬不要刪除其中任何一個):

index.save('/data/deerwester.index')

index = similarities.MatrixSimilarity.load('/data/deerwester.index')

  如果加入TFIDF,在使用LSI,需要先轉化為TFIDF向量,在轉化為LSI向量

  tfidf_query = models.TfidfModel(query)

  query_vec = lsi_model[tfidf_query]

 5.轉化為sklearn和scripy格式

     gensim的相似度匹配,用於文字分類時準確率不高,而在sklearn中有很多機器學習和深度學習演算法,兩者的資料格式不符。sklearn的輸入和numpy和scripy相關,如果是密集矩陣,使用numpy.array格式,如果是稀疏矩陣,使用scipy.sparse.csr_matrix格式,可以去 scipy的官網檢視相關文件,其中第四種方式比較簡單:

def sparse2dense(lsi_corpus_total):

     data = []

     rows = []

     cols = []

     line_count = 0

     for line in lsi_corpus_total: # lsi_corpus_total 是之前由gensim生成的lsi向量

      for elem in line:

         rows.append(line_count)

         cols.append(elem[0])

         data.append(elem[1])

         line_count += 1

   lsi_sparse_matrix = csr_matrix(data, (rows,cols)) 

  其他方式

import gensim

import numpy as np

corpus = gensim.matutils.Dense2Corpus(numpy_matrix)

numpy_matrix = gensim.matutils.corpus2dense(corpus, num_terms=number_of_corpus_features)

import scipy.sparse

corpus = gensim.matutils.Sparse2Corpus(scipy_sparse_matrix)

scipy_csc_matrix = gensim.matutils.corpus2csc(corpus)