lda主題模型python實現篇
個人部落格地址:http://xurui.club/2018/06/01/lda/
最近在做一個動因分析的專案,自然想到了主題模型LDA。這次先把模型流程說下,原理後面再講。
lda實現有很多開源庫,這裡用的是gensim.
1 文字預處理
大概說下文字的樣子,LDA是無監督模型,也就是說不需要標籤,只要傳入文字就好。LDA要學習文件-主題分佈和主題-詞分佈,所以我們把一個人的資料join在一起作為一條文件。對文件進行分詞,使用的jieba分詞工具包。注意,這裡要做去停用詞處理,包括標點和一些沒用的詞,如“呵呵”,“哈哈”。做專案時,第一版沒有去無用詞,最後提出的主題都是“你”“我”“他”“你好”這樣的東西,去掉之後可以較好提高結果質量。
2 將上步處理的結果進行格式化表示
即將所有文件數表示成m*n的矩陣D,m表示有m篇文件,n表示這篇文件有n個詞,n不定長。
3 生成詞典
用gensim.corpora.Dictionary包
這個包講下吧
from gensim.corpora import Dictionary
text = [['我', '想吃', '大龍蝦', '和', '烤豬蹄']]
dictionary = Dictionary(text)
print((dictionary))
doc = dictionary.doc2bow(['我', '想吃', '大龍蝦', '和', '我','你' ,'烤豬蹄'])
print(doc)
#####output#####
Dictionary(5 unique tokens: ['我', '大龍蝦', '想吃', '和', '烤豬蹄'])
[(0, 1), (1, 1), (2, 2), (3, 1), (4, 1)]
可以看出,我們把我想吃大龍蝦和烤豬蹄編成字典,共五個詞,這裡輸出結果裡看不出是個字典,其實是有下標的,0對應我,1對應大龍蝦,…4對應烤豬蹄。
然後我們在下一步將文字變成詞袋,這裡用的文字是[‘我’, ‘想吃’, ‘大龍蝦’, ‘和’, ‘我’,’你’,’烤豬蹄’],注意文字格式也是詞為元素的列表。這句話是我自己構造的,只是為了說兩點,語法請忽略。第一點:“我”這個詞出現了兩次,所以下標為2的地方,值為2;第二點,“你”這個詞出現了1次,可是在詞典中沒有,所有直接被忽略。
這樣就可以用字典,將文字表示成詞袋模型,詞袋模型不懂的,見我另一篇文章,自然語言處理NLP的詞如何表示。當我們做完了LDA模型後,對於新的文字,我們想看下它所在的主題分佈,就要使用該字典再進行詞袋編碼,也就是說這個字典,我們以後也會用到,所以,我們在這裡把詞典儲存起來。
儲存詞典可以用pickle,很好用。不懂的見我另一篇文章,神奇的pickle。
4 訓練LDA模型
這裡用的是gensim.models.ldamodel包
ldamodel = LdaModel(text, num_topics=10, id2word=dictionary, passes=20)
使用這句話就可以直接訓練LDA模型了,講一下引數吧。
text:文字,已經表示成詞袋了。
num_topics: 提取的主題數
id2word:詞典
passes:類似於在機器學習中常見的epoch,也就是訓練了多少輪。
然後我們得到了訓練好的ldamodel.用這個模型可以做哪些事情呢?
5 ldamodel使用
可以輸出這個模型的各個主題下的主題詞
print(ldamodel.print_topics(num_topics=10, num_words=10))
###output###
[(0, '0.015*"說" + 0.011*"吃" + 0.008*"想" + 0.007*"睡" + 0.005*"\u2005" + 0.005*"做" + 0.005*"明天" + 0.005*"買" + 0.005*"幹嘛" + 0.005*"玩"'),
(1, '0.017*" " + 0.010*"說" + 0.004*"吃" + 0.004*"許華升" + 0.004*"\x14" + 0.004*"想" + 0.003*"做" + 0.003*"買" + 0.003*"ÿ" + 0.003*"錢"'),
(2, '0.008*"com" + 0.007*" " + 0.004*"手機" + 0.003*"女" + 0.003*"說" + 0.003*"www" + 0.003*"cc" + 0.002*"號" + 0.002*"qq" + 0.002*"視訊"'),
(3, '0.007*"com" + 0.006*" " + 0.005*"38" + 0.004*"號" + 0.004*"貸" + 0.003*"3000" + 0.003*"10" + 0.003*"做" + 0.003*"說" + 0.002*"111"'),
(4, '0.017*" " + 0.007*"說" + 0.006*"做" + 0.005*"你好" + 0.005*"吃" + 0.004*"號" + 0.004*"\u2005" + 0.004*"想" + 0.003*"錢" + 0.003*"明天"'),
(5, '0.013*" " + 0.012*"說" + 0.007*"吃" + 0.006*"想" + 0.005*"睡" + 0.005*"做" + 0.004*"錢" + 0.004*"買" + 0.004*"回來" + 0.004*"幹嘛"'),
(6, '0.010*" " + 0.005*"買大單" + 0.005*"貸" + 0.004*"說" + 0.004*"貸款" + 0.004*"錢" + 0.003*"com" + 0.003*"號" + 0.003*"奧特曼" + 0.003*"吃"'),
(7, '0.022*" " + 0.010*"說" + 0.008*"做" + 0.007*"吃" + 0.005*"想" + 0.004*"錢" + 0.003*"\u2005" + 0.003*"買" + 0.003*"謝謝" + 0.003*"明天"'),
(8, '0.017*" " + 0.015*"com" + 0.006*"www" + 0.005*"說" + 0.004*"號" + 0.004*"\u2005" + 0.003*"手機" + 0.003*"錢" + 0.003*"吃" + 0.003*"https"'),
(9, '0.011*"\u2005" + 0.011*"說" + 0.010*"做" + 0.009*" " + 0.004*"錢" + 0.004*"買" + 0.004*"發" + 0.003*"謝謝" + 0.003*"吃" + 0.003*"玩"')]
這裡隨便找了些資料,效果不是太明顯,這裡主要講處理流程,不要被這結果乾擾心情,不過工業應用中很多時候,實際結果和你理想的結果有很大差距。用一些正常的資料,是可以看出一些資訊的。上次用汽車之家的評論資料做lda,主題資訊就比較明顯,有關於油耗的,有關於買車的等等。
也可以對新文字,找出其所在的主題分佈。
def to_lda_vec(model, dictionary, text_list=None):
'''
:param model: lda model
:param dictionary: Dictionary for toBow
:param text_list: texts
:return: texts about one topic
'''
lda_list = []
for texts in text_list:
doc_bow = dictionary.doc2bow(texts)
doc_lda = model[doc_bow]
lda_list.append(doc_lda)
return lda_list
這個方法中的引數加了註釋,這裡可以看到有個引數是dictionary,這裡就是我們前面訓練lda時用的詞典,前面儲存的詞典派上用場了。最後輸出的lda_list是一個列表,列表中元素為每句話的doc_lda,doc_lda是這樣子的[(5,0.342345),(6,0.1111)…],也就是個list,無素為元組,元組包括兩個值,第一個值表示主題id,第二個值表示屬於該主題的概率。
也可以用於新文字資料的向量化,即將新的文字對映成主題向量,然後可以做分類,做聚類,做推薦。