1. 程式人生 > >lda主題模型python實現篇

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,第二個值表示屬於該主題的概率。

也可以用於新文字資料的向量化,即將新的文字對映成主題向量,然後可以做分類,做聚類,做推薦。