Gensim是一款開(kāi)源的第三方Python工具包,用于從原始的非結(jié)構(gòu)化的文本中,無(wú)監(jiān)督地學(xué)習(xí)到文本隱層的主題向量表達(dá)。?
支持包括TF-IDF,LSA,LDA,和word2vec在內(nèi)的多種主題模型算法,?
支持流式訓(xùn)練,并提供了諸如相似度計(jì)算,信息檢索等一些常用任務(wù)的API接口
1.基本概念
語(yǔ)料(Corpus):一組原始文本的集合,用于無(wú)監(jiān)督地訓(xùn)練文本主題的隱層結(jié)構(gòu)。語(yǔ)料中不需要人工標(biāo)注的附加信息。在Gensim中,Corpus通常是一個(gè)可迭代的對(duì)象(比如列表)。每一次迭代返回一個(gè)可用于表達(dá)文本對(duì)象的稀疏向量。
向量(Vector):由一組文本特征構(gòu)成的列表。是一段文本在Gensim中的內(nèi)部表達(dá)。
稀疏向量(SparseVector):通常,我們可以略去向量中多余的0元素。此時(shí),向量中的每一個(gè)元素是一個(gè)(key, value)的元組
模型(Model):是一個(gè)抽象的術(shù)語(yǔ)。定義了兩個(gè)向量空間的變換(即從文本的一種向量表達(dá)變換為另一種向量表達(dá))。
2.步驟一:訓(xùn)練語(yǔ)料的預(yù)處理
由于Gensim使用python語(yǔ)言開(kāi)發(fā)的,為了減少安裝中的繁瑣,直接使用anaconda工具進(jìn)行集中安裝,?
輸入:pip install gensim,這里不再贅述。
訓(xùn)練語(yǔ)料的預(yù)處理指的是將文檔中原始的字符文本轉(zhuǎn)換成Gensim模型所能理解的稀疏向量的過(guò)程。
通常,我們要處理的原生語(yǔ)料是一堆文檔的集合,每一篇文檔又是一些原生字符的集合。在交給Gensim的模型訓(xùn)練之前,我們需要將這些原生字符解析成Gensim能處理的稀疏向量的格式。由于語(yǔ)言和應(yīng)用的多樣性,我們需要先對(duì)原始的文本進(jìn)行分詞、去除停用詞等操作,得到每一篇文檔的特征列表。例如,在詞袋模型中,文檔的特征就是其包含的word:
texts = [['human', 'interface', 'computer'],
['survey', 'user', 'computer', 'system', 'response', 'time'],
['eps', 'user', 'interface', 'system'],
['system', 'human', 'system', 'eps'],
['user', 'response', 'time'],
['trees'],
['graph', 'trees'],
['graph', 'minors', 'trees'],
['graph', 'minors', 'survey']]
其中,corpus的每一個(gè)元素對(duì)應(yīng)一篇文檔。
接下來(lái),我們可以調(diào)用Gensim提供的API建立語(yǔ)料特征(此處即是word)的索引字典,并將文本特征的原始表達(dá)轉(zhuǎn)化成詞袋模型對(duì)應(yīng)的稀疏向量的表達(dá)。依然以詞袋模型為例:
from gensim import corpora
dictionary = corpora.Dictionary(texts)
corpus = [dictionary.doc2bow(text) for text in texts]
print corpus[0] # [(0, 1), (1, 1), (2, 1)]
到這里,訓(xùn)練語(yǔ)料的預(yù)處理工作就完成了。我們得到了語(yǔ)料中每一篇文檔對(duì)應(yīng)的稀疏向量(這里是bow向量);向量的每一個(gè)元素代表了一個(gè)word在這篇文檔中出現(xiàn)的次數(shù)。值得注意的是,雖然詞袋模型是很多主題模型的基本假設(shè),這里介紹的doc2bow函數(shù)并不是將文本轉(zhuǎn)化成稀疏向量的唯一途徑。在下一小節(jié)里我們將介紹更多的向量變換函數(shù)。
最后,出于內(nèi)存優(yōu)化的考慮,Gensim支持文檔的流式處理。我們需要做的,只是將上面的列表封裝成一個(gè)Python迭代器;每一次迭代都返回一個(gè)稀疏向量即可。
class MyCorpus(object):
def __iter__(self):
? ?for line in open('mycorpus.txt'):
? ? ? ?# assume there's one document per line, tokens ? ? ? ? ? ? ? ? ? separated by whitespace
? ? ? ?yield dictionary.doc2bow(line.lower().split())
3.步驟二:主題向量的變換
對(duì)文本向量的變換是Gensim的核心。通過(guò)挖掘語(yǔ)料中隱藏的語(yǔ)義結(jié)構(gòu)特征,我們最終可以變換出一個(gè)簡(jiǎn)潔高效的文本向量。
在Gensim中,每一個(gè)向量變換的操作都對(duì)應(yīng)著一個(gè)主題模型,例如上一小節(jié)提到的對(duì)應(yīng)著詞袋模型的doc2bow變換。每一個(gè)模型又都是一個(gè)標(biāo)準(zhǔn)的Python對(duì)象。下面以TF-IDF模型為例,介紹Gensim模型的一般使用方法。
首先是模型對(duì)象的初始化。通常,Gensim模型都接受一段訓(xùn)練語(yǔ)料(注意在Gensim中,語(yǔ)料對(duì)應(yīng)著一個(gè)稀疏向量的迭代器)作為初始化的參數(shù)。顯然,越復(fù)雜的模型需要配置的參數(shù)越多。
from gensim import models
tfidf = models.TfidfModel(corpus)
其中,corpus是一個(gè)返回bow向量的迭代器。這兩行代碼將完成對(duì)corpus中出現(xiàn)的每一個(gè)特征的IDF值的統(tǒng)計(jì)工作。
接下來(lái),我們可以調(diào)用這個(gè)模型將任意一段語(yǔ)料(依然是bow向量的迭代器)轉(zhuǎn)化成TFIDF向量(的迭代器)。需要注意的是,這里的bow向量必須與訓(xùn)練語(yǔ)料的bow向量共享同一個(gè)特征字典(即共享同一個(gè)向量空間)。
doc_bow = [(0, 1), (1, 1)]
print tfidf[doc_bow] # [(0, 0.70710678), (1, 0.70710678)]
注意,同樣是出于內(nèi)存的考慮,model[corpus]方法返回的是一個(gè)迭代器。如果要多次訪問(wèn)model[corpus]的返回結(jié)果,可以先將結(jié)果向量序列化到磁盤(pán)上。
我們也可以將訓(xùn)練好的模型持久化到磁盤(pán)上,以便下一次使用:
tfidf.save("./model.tfidf")
tfidf = models.TfidfModel.load("./model.tfidf")
Gensim內(nèi)置了多種主題模型的向量變換,包括LDA,LSI,RP,HDP等。這些模型通常以bow向量或tfidf向量的語(yǔ)料為輸入,生成相應(yīng)的主題向量。所有的模型都支持流式計(jì)算。關(guān)于Gensim模型更多的介紹,可以參考這里:API Reference(https://radimrehurek.com/gensim/apiref.html)
4.步驟三:文檔相似度的計(jì)算
在得到每一篇文檔對(duì)應(yīng)的主題向量后,我們就可以計(jì)算文檔之間的相似度,進(jìn)而完成如文本聚類、信息檢索之類的任務(wù)。在Gensim中,也提供了這一類任務(wù)的API接口。
以信息檢索為例。對(duì)于一篇待檢索的query,我們的目標(biāo)是從文本集合中檢索出主題相似度最高的文檔。
首先,我們需要將待檢索的query和文本放在同一個(gè)向量空間里進(jìn)行表達(dá)(以LSI向量空間為例):
# 構(gòu)造LSI模型并將待檢索的query和文本轉(zhuǎn)化為L(zhǎng)SI主題向量
# 轉(zhuǎn)換之前的corpus和query均是BOW向量
lsi_model = models.LsiModel(corpus, id2word=dictionary, ? ? ? ? ?num_topics=2)
documents = lsi_model[corpus]
query_vec = lsi_model[query]
接下來(lái),我們用待檢索的文檔向量初始化一個(gè)相似度計(jì)算的對(duì)象:
index = similarities.MatrixSimilarity(documents)
我們也可以通過(guò)save()和load()方法持久化這個(gè)相似度矩陣:
index.save('/tmp/test.index')
index = similarities.MatrixSimilarity.load('/tmp/test.index')
注意,如果待檢索的目標(biāo)文檔過(guò)多,使用similarities.MatrixSimilarity類往往會(huì)帶來(lái)內(nèi)存不夠用的問(wèn)題。此時(shí),可以改用similarities.Similarity類。二者的接口基本保持一致。
最后,我們借助index對(duì)象計(jì)算任意一段query和所有文檔的(余弦)相似度:
sims = index[query_vec]
#返回一個(gè)元組類型的迭代器:(idx, sim)
5.補(bǔ)充
TF-IDF
TF-IDF(注意:這里不是減號(hào))是一種統(tǒng)計(jì)方法,用以評(píng)估一字詞對(duì)于一個(gè)文件集或一個(gè)語(yǔ)料庫(kù)中的其中一份文件的重要程度。?
字詞的重要性隨著它在文件中出現(xiàn)的次數(shù)成正比增加,但同時(shí)會(huì)隨著它在語(yǔ)料庫(kù)中出現(xiàn)的頻率成反比下降。TF-IDF加權(quán)的各種形式常被搜索引擎應(yīng)用,作為文件與用戶查詢之間相關(guān)程度的度量或評(píng)級(jí)。?
1. 一個(gè)詞預(yù)測(cè)主題能力越強(qiáng),權(quán)重就越大,反之,權(quán)重就越小。我們?cè)诰W(wǎng)頁(yè)中看到“原子能”這個(gè)詞,或多或少地能了解網(wǎng)頁(yè)的主題。我們看到“應(yīng)用”一次,對(duì)主題基本上還是一無(wú)所知。因此,“原子能“的權(quán)重就應(yīng)該比應(yīng)用大。?
2. 應(yīng)刪除詞的權(quán)重應(yīng)該是零。
LDA文檔主題生成模型
LDA是一種文檔主題生成模型,包含詞、主題和文檔三層結(jié)構(gòu)。
所謂生成模型,就是說(shuō),我們認(rèn)為一篇文章的每個(gè)詞都是通過(guò)“以一定概率選擇了某個(gè)主題,并從這個(gè)主題中以一定概率選擇某個(gè)詞語(yǔ)”這樣一個(gè)過(guò)程得到。文檔到主題服從多項(xiàng)式分布,主題到詞服從多項(xiàng)式分布。
LDA是一種非監(jiān)督機(jī)器學(xué)習(xí)技術(shù),可以用來(lái)識(shí)別大規(guī)模文檔集或語(yǔ)料庫(kù)中潛藏的主題信息。它采用了詞袋的方法,這種方法將每一篇文檔視為一個(gè)詞頻向量,從而將文本信息轉(zhuǎn)化為了易于建模的數(shù)字信息。
但是詞袋方法沒(méi)有考慮詞與詞之間的順序,這簡(jiǎn)化了問(wèn)題的復(fù)雜性,同時(shí)也為模型的改進(jìn)提供了契機(jī)。每一篇文檔代表了一些主題所構(gòu)成的一個(gè)概率分布,而每一個(gè)主題又代表了很多單詞所構(gòu)成的一個(gè)概率分布.