gensim是一個python的自然語言處理庫,能夠將文檔根據TF-IDF, LDA, LSI 等模型轉化成向量模式,以便進行進一步的處理。此外,gensim還實現了word2vec功能,能夠將單詞轉化為詞向量。
1. corpora 和 dictionary
-
基本概念和用法:
corpora是gensim中的一個基本概念,是文檔集的表現形式,也是后續進一步處理的基礎。從本質上來說,corpora其實是一種格式或者說約定,其實就是一個二維矩陣。在實際運行中,因為單詞數量極多(上萬甚至10萬級別),而一篇文檔的單詞數是有限的,所以如果還是采用密集矩陣來表示的話,會造成極大的內存浪費,所以gensim內部是用稀疏矩陣的形式來表示的。
- 包名
from gensim import corpora from collections import defaultdict
2. 詞典操作
將文檔分割成詞語之后,使用dictionary = corpora.Dictionary(texts)生成詞典。並可以使用save函數將詞典持久化。
dictionary.save('/tmp/deerwester.dict')
生成詞典以后corpus = [dictionary.doc2bow(text) for text in texts]檔轉化為向量形式。
from gensim import corpora from collections import defaultdict documents = ["Human machine interface for lab abc computer applications", "A survey of user opinion of computer system response time", "The EPS user interface management system", "System and human system engineering testing of EPS", "Relation of user perceived response time to error measurement", "The generation of random binary unordered trees", "The intersection graph of paths in trees", "Graph minors IV Widths of trees and well quasi ordering", "Graph minors A survey"] # 去掉停用詞 stoplist = set('for a of the and to in'.split()) texts = [[word for word in document.lower().split() if word not in stoplist] for document in documents] # 去掉只出現一次的單詞 frequency = defaultdict(int) for text in texts: for token in text: frequency[token] += 1 texts = [[token for token in text if frequency[token] > 1] for text in texts] dictionary = corpora.Dictionary(texts) # 生成詞典 # 將文檔存入字典,字典有很多功能,比如 # diction.token2id 存放的是單詞-id key-value對 # diction.dfs 存放的是單詞的出現頻率 dictionary.save('/tmp/deerwester.dict') # store the dictionary, for future reference corpus = [dictionary.doc2bow(text) for text in texts] corpora.MmCorpus.serialize('/tmp/deerwester.mm', corpus) # store to disk, for later use
3. 存儲
- 存儲文件
dictionary.save('/tmp/deerwester.dict')
- 序列化
corpora.MmCorpus.serialize 將corpus持久化到磁盤中。
corpora.MmCorpus.serialize('/tmp/deerwester.mm', corpus)
- 反序列化:
corpus = corpora.MmCorpus('/tmp/deerwester.mm')
除了MmCorpus以外,還有其他的格式,例如SvmLightCorpus, BleiCorpus, LowCorpus等等,用法類似。
4. 其他操作
# 過濾掉出現頻率最高的N個單詞 dictionary.filter_n_most_frequent(N) # 1.去掉出現次數低於no_below的 # 2.去掉出現次數高於no_above的。注意這個小數指的是百分數 # 3.在1和2的基礎上,保留出現頻率前keep_n的單詞 dictionary.filter_extremes(no_below=5, no_above=0.5, keep_n=100000) # 有兩種用法,一種是去掉bad_id對應的詞,另一種是保留good_id對應的詞而去掉其他詞。注意這里bad_ids和good_ids都是列表形式 dictionary.filter_tokens(bad_ids=None, good_ids=None) # 在執行完前面的過濾操作以后,可能會造成單詞的序號之間有空隙,這時就可以使用該函數來對詞典來進行重新排序,去掉這些空隙。 dictionary.compacity()
5. 分批處理和分布式計算
當文本的規模很大時,也許會造成內存不足以容納文本的情況,這就需要將所有文本分批處理,最后再將各批次計算得到的結果進行匯總。分布式計算時也有類似的需求。
這里假設在兩個批次中,分別生成了dict1,corpus1以及dict2,corpus2.
第一步,首先將兩個詞典合並。當然,如果是先統一生成詞典再分批生成詞向量的話,可以跳過這一步,因為詞典是一樣的。
dict2_to_dict1 = dict1.merge_with(dict2)
要注意的是,得到的dict2_to_dict1並不是生成后的詞典,而是dict2中的單詞序號到這些詞在合並后詞典新序號的映射表。而dict1本身成為合並后的新詞典。
第二步,合並corpus
如果之前跳過了第一步,即dict1就是dict2的話,可以直接進行合並。合並有兩種方式,一種是
merged_corpus = [x for x in corpus1] + [x for x in corpus2]
另外一種,則需使用內置的itertools類
merged_corpus = itertools.chain(corpus1, corpus2) merged_corpus = [x for x in merged_corpus]
如果之前的詞典也是分批生成的話,則需要對corpus2進行一定的處理
new_corpus2 = dict2_to_dict1[corpus2] merged_corpus = itertools.chain(corpus1, new_corpus2) merged_corpus = [x for x in merged_corpus]
這樣,就把分批處理得到的dict和corpus都合並起來了。
6. models
在models中,可以對corpus進行進一步的處理,比如使用tf-idf模型,lsi模型,lda模型等,非常強大。
在按照之前的方法生成了corpus和dictionary以后,就可以生成模型了。
tfidf_model = models.TfidfModel(corpus)
注意,目前只是生成了一個模型,但這是類似於生成器,並不是將對應的corpus轉化后的結果。對tf-idf模型而言,里面存儲有各個單詞的詞頻,文頻等信息。想要將文檔轉化成tf-idf模式表示的向量,還要使用如下命令
corpus_tfidf = tfidf_model[corpus]
對於lda和lsi模型,用法有所不同
lsi_model = models.LsiModel(corpus_tfidf, id2word=dictionary, num_topics=2)
corpus_lsi = lsi_model[corpus_tfidf]
可以看到,這里除了corpus以外,還多了num_topic的選項。這是指的潛在主題(topic)的數目,也等於轉成lsi模型以后每個文檔對應的向量長度。轉化以后的向量在各項的值,即為該文檔在該潛在主題的權重。因此lsi和lda的結果也可以看做該文檔的文檔向量,用於后續的分類,聚類等算法。值得注意的是,id2word是所有模型都有的選項,可以指定使用的詞典。
- 代碼示例:
import os from gensim import corpora, models, similarities from pprint import pprint from matplotlib import pyplot as plt import logging # logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) def PrintDictionary(dictionary): token2id = dictionary.token2id dfs = dictionary.dfs token_info = {} for word in token2id: token_info[word] = dict( word = word, id = token2id[word], freq = dfs[token2id[word]] ) token_items = token_info.values() token_items = sorted(token_items, key = lambda x:x['id']) print('The info of dictionary: ') pprint(token_items) print('--------------------------') def Show2dCorpora(corpus): nodes = list(corpus) ax0 = [x[0][1] for x in nodes] # 繪制各個doc代表的點 ax1 = [x[1][1] for x in nodes] # print(ax0) # print(ax1) plt.plot(ax0,ax1,'o') plt.show() if (os.path.exists("/tmp/deerwester.dict")): dictionary = corpora.Dictionary.load('/tmp/deerwester.dict') corpus = corpora.MmCorpus('/tmp/deerwester.mm') print("Used files generated from first tutorial") else: print("Please run first tutorial to generate data set") PrintDictionary(dictionary) # 嘗試將corpus(bow形式) 轉化成tf-idf形式 tfidf_model = models.TfidfModel(corpus) # step 1 -- initialize a model 將文檔由按照詞頻表示 轉變為按照tf-idf格式表示 doc_bow = [(0, 1), (1, 1),[4,3]] doc_tfidf = tfidf_model[doc_bow] # 將整個corpus轉為tf-idf格式 corpus_tfidf = tfidf_model[corpus] # pprint(list(corpus_tfidf)) # pprint(list(corpus)) ## LSI模型 ************************************************** # 轉化為lsi模型, 可用作聚類或分類 lsi_model = models.LsiModel(corpus_tfidf, id2word=dictionary, num_topics=2) corpus_lsi = lsi_model[corpus_tfidf] nodes = list(corpus_lsi) # pprint(nodes) lsi_model.print_topics(2) # 打印各topic的含義 # ax0 = [x[0][1] for x in nodes] # 繪制各個doc代表的點 # ax1 = [x[1][1] for x in nodes] # print(ax0) # print(ax1) # plt.plot(ax0,ax1,'o') # plt.show() lsi_model.save('/tmp/model.lsi') # same for tfidf, lda, ... lsi_model = models.LsiModel.load('/tmp/model.lsi') # ********************************************************* ## LDA模型 ************************************************** lda_model = models.LdaModel(corpus_tfidf, id2word=dictionary, num_topics=2) corpus_lda = lda_model[corpus_tfidf] Show2dCorpora(corpus_lsi) # nodes = list(corpus_lda) # pprint(list(corpus_lda)) # 此外,還有Random Projections, Hierarchical Dirichlet Process等模型
7. similarities
這一部分主要負責計算文檔間的相似度。與向量的相似度計算方式一樣,采用余弦方法計算得到。一般來講,使用lsi模型得到的向量進行計算效果比較好。
- 代碼示例
corpus_simi_matrix = similarities.MatrixSimilarity(corpus_lsi) # 計算一個新的文本與既有文本的相關度 test_text = "Human computer interaction".split() test_bow = dictionary.doc2bow(test_text) test_tfidf = tfidf_model[test_bow] test_lsi = lsi_model[test_tfidf] test_simi = corpus_simi_matrix[test_lsi] print(list(enumerate(test_simi)))
得到結果[(0, 0.99916452), (1, 0.99632162), (2, 0.9990505), (3, 0.99886364), (4, 0.99996823), (5, -0.058117405), (6, -0.021589279), (7, 0.013524055), (8, 0.25163394)]。可以看到顯然屬於第一類。
轉載自:https://www.cnblogs.com/wangqingyi/articles/5911647.html
