A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本篇是我的LDA主题挖掘系列的第三篇,专门来介绍如何对训练好的LDA模型进行评价。

训练好好LDA主题模型后,如何评价模型的好坏?能否直接将训练好的模型拿去应用?这是一个比较重要的问题,在对模型精度要求比较高的项目或科研中,需要对模型进行评价。一般来说,LDA模型的主题数量都是需要需要根据具体任务进行调整的,即要评价不同主题数的模型的困惑度来选择最优的那个模型。

那么,困惑度是什么?
1.LDA主题模型困惑度
这部分参照:LDA主题模型评估方法–Perplexity,不过后面发现这篇文章Perplexity(困惑度)感觉写的更好一点,两篇都是翻译的维基百科。
perplexity是一种信息理论的测量方法,b的perplexity值定义为基于b的熵的能量(b可以是一个概率分布,或者概率模型),通常用于概率模型的比较
wiki上列举了三种perplexity的计算:
1.1 概率分布的perplexity
公式:
其中H(p)就是该概率分布的熵。当概率P的K平均分布的时候,带入上式可以得到P的perplexity值=K。
1.2 概率模型的perplexity
公式:
公式中的Xi为测试局,可以是句子或者文本,N是测试集的大小(用来归一化),对于未知分布q,perplexity的值越小,说明模型越好。
指数部分也可以用交叉熵来计算,略过不表。
1.3单词的perplexity
perplexity经常用于语言模型的评估,物理意义是单词的编码大小。例如,如果在某个测试语句上,语言模型的perplexity值为2^190,说明该句子的编码需要190bits
2.困惑度perplexity公式


perplexity=e−∑log(p(w))Nperplexity=e−∑log(p(w))N


其中,p(w)是指的测试集中出现的每一个词的概率,具体到LDA的模型中就是p(w)=∑zp(z|d)∗p(w|z)p(w)=∑zp(z|d)∗p(w|z) (z,d分别指训练过的主题和测试集的各篇文档)。分母的N是测试集中出现的所有词,或者说是测试集的总长度,不排重。
3.计算困惑度的代码
下述代码中加载的.dictionary(字典)、.mm(语料)、.model(模型)文件均为在python下进行lda主题挖掘(二)——利用gensim训练LDA模型中得到的结果,如果文件格式与我不同,说明调用的不是同一个包,代码无法直接使用,可参考代码逻辑,若是已按照python下进行lda主题挖掘(二)——利用gensim训练LDA模型中的方法得到上述文件,可直接调用下述代码计算困惑度。
PS:将语料经过TFIDF训练模型后计算得到的困惑度要远大于直接进行训练的困惑度(在我这边是这样),应该是正常情况,不必惊慌。
#-*-coding:utf-8-*-import sysreload(sys)sys.setdefaultencoding('utf-8')import osfrom gensim.corpora import Dictionaryfrom gensim import corpora, modelsfrom datetime import datetimeimport logginglogging.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"""        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.0006211180124223594),...]    for doc in testset:        doc_topics_ist.append(ldamodel.get_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        doc_word_num = 0 # the num of words in the doc        for word_id, num in doc:            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[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 = math.exp(-prob_doc_sum/testset_word_num) # perplexity = exp(-sum(p(d)/sum(Nd))    print ("the perplexity of this ldamodel is : %s"%prep)    return prepif __name__ == '__main__':    middatafolder = r'E:\work\lda' + os.sep    dictionary_path = middatafolder + 'dictionary.dictionary'    corpus_path = middatafolder + 'corpus.mm'    ldamodel_path = middatafolder + 'lda.model'    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)

3 个回复

倒序浏览
奈斯
回复 使用道具 举报
回复 使用道具 举报
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马