python 下进⾏lda 主题挖掘(三)——计算困惑度perplexity
到2018年3⽉7⽇为⽌,本系列三篇⽂章已写完,可能后续有新的内容的话会继续更新。
本篇是我的LDA主题挖掘系列的第三篇,专门来介绍如何对训练好的LDA模型进⾏评价。
训练好好LDA主题模型后,如何评价模型的好坏?能否直接将训练好的模型拿去应⽤?这是⼀个⽐较重要的问题,在对模型精度要求⽐较⾼的项⽬或科研中,需要对模型进⾏评价。⼀般来说,LDA模型的主题数量都是需要需要根据具体任务进⾏调整的,即要评价不同主题数的模型的困惑度来选择最优的那个模型。
那么,困惑度是什么?
1.LDA主题模型困惑度
这部分参照:,不过后⾯发现这篇⽂章感觉写的更好⼀点,两篇都是翻译的。
perplexity是⼀种信息理论的测量⽅法,b的perplexity值定义为基于b的熵的能量(b可以是⼀个概率分布,或者概率模型),通常⽤于概率模型的⽐较
wiki上列举了三种perplexity的计算:
1.1 概率分布的perplexity
公式:
其中H§就是该概率分布的熵。当概率P的K平均分布的时候,带⼊上式可以得到P的perplexity值=K。
1.2 概率模型的perplexity 公式:
公式中的Xi为测试局,可以是句⼦或者⽂本,N是测试集的⼤⼩(⽤来归⼀化),对于未知分布q,perplexity的值越⼩,说明模型越好。指数部分也可以⽤交叉熵来计算,略过不表。
1.3单词的perplexity
perplexity经常⽤于语⾔模型的评估,物理意义是单词的编码⼤⼩。例如,如果在某个测试语句上,语⾔模型的perplexity值为2^190,说明该句⼦的编码需要190bits
2.困惑度perplexity公式
其中,**p(w)**是指的测试集中出现的每⼀个词的概率,具体到LDA的模型中就是 (z,d分别指训练过的
主题和测试集的各篇⽂档)。分母的N是测试集中出现的所有词,或者说是测试集的总长度,不排重。
3.计算困惑度的代码
下述代码中加载的.dictionary(字典)、.mm(语料)、.model(模型)⽂件均为在中得到的结果,如果⽂件格式与我不同,说明调⽤的不是同⼀个包,代码⽆法直接使⽤,可参考代码逻辑,若是已按照中的⽅法得到上述⽂件,可直接调⽤下述代码计算困惑度。
PS:将语料经过TFIDF训练模型后计算得到的困惑度要远⼤于直接进⾏训练的困惑度(在我这边是这样),应该是正常情况,不必惊慌。
perplexity =e N
−log (p (w ))∑p (w )=zp (z ∣d )∗∑p (w ∣z )
#-*-coding:utf-8-*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import os
pora import Dictionary
from gensim import corpora, models
from datetime import datetime
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s : ', level=logging.INFO)
def perplexity(ldamodel, testset, dictionary, size_dictionary, num_topics):
"""calculate the perplexity of a lda-model"""
# dictionary : {7822:'deferment', 1841:'circuitry',19202:'fabianism'...]
print('the info of this ldamodel: \n')
print('num of testset: %s; size_dictionary: %s; num of topics: %s'%(len(testset), size_dictionary, num_topics))
prep =0.0
prob_doc_sum =0.0
topic_word_list =[]# store the probablity of topic-word:[(u'business', 0.010020942661849608),(u'family', 0.0088027946271537413)...] for topic_id in range(num_topics):
topic_word = ldamodel.show_topic(topic_id, size_dictionary)
dic ={}
for word, probability in topic_word:
dic[word]= probability
topic_word_list.append(dic)
doc_topics_ist =[]#store the doc-topic tuples:[(0, 0.0006211180124223594),(1, 0.0006211180124223
594),...]
for doc in testset:
doc_topics_ist._document_topics(doc, minimum_probability=0))
testset_word_num =0
for i in range(len(testset)):
prob_doc =0.0# the probablity of the doc
doc = testset[i]
doc_word_num =0# the num of words in the doc
for word_id, num in doc.items():
prob_word =0.0# the probablity of the word
doc_word_num += num
word = dictionary[word_id]
for topic_id in range(num_topics):
# cal p(w) : p(w) = sumz(p(z)*p(w|z))
prob_topic = doc_topics_ist[i][topic_id][1]
prob_topic_word = topic_word_list[topic_id][word]
prob_word += prob_topic*prob_topic_word
prob_doc += math.log(prob_word)# p(d) = sum(log(p(w)))
prob_doc_sum += prob_doc
testset_word_num += doc_word_num
prep = p(-prob_doc_sum/testset_word_num)# perplexity = exp(-sum(p(d)/sum(Nd))
print("the perplexity of this ldamodel is : %s"%prep)
java调用python模型return prep
if __name__ =='__main__':
middatafolder = r'E:\work\lda'+ os.sep
dictionary_path = middatafolder +'dictionary.dictionary'
corpus_path = middatafolder +''
ldamodel_path = middatafolder +'del'
dictionary = corpora.Dictionary.load(dictionary_path)
corpus = corpora.MmCorpus(corpus_path)
lda_multi = models.ldamodel.LdaModel.load(ldamodel_path)
num_topics =50
testset =[]
# sample 1/300
for i in range(corpus.num_docs/300):
testset.append(corpus[i*300])
prep = perplexity(lda_multi, testset, dictionary,len(dictionary.keys()), num_topics)
参考资料
1.
2. java写的代码,本博客中的代码是参照改博客函数写的。
3.
以上,欢迎交流。
代码略为粗糙,如有问题,请务必指正,感激不尽。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论