今天我们来谈谈主题模型(Latent Dirichlet Allocation),由于主题模型是生成模型,而我们常用的决策树,支持向量机,CNN等常用的机器学习模型的都是判别模型。所以笔者首先简单介绍一下判别模型和生成模型。下面笔者列出了生成模型和判别模型的核心区别:
- 判别模型:估计的是条件概率分布(conditional distribution)——作为预测模型。
- 生成模型:估计的是联合概率分布(joint probability distribution)——,然后根据贝叶斯公式 求出条件概率分布作为预测模型
简单的说:
判别模型只需要学习特征x,从而就可以去预测类别y。做预测时是判断新数据属于哪个类别的概率最大,进而确定新数据的类别,判别模型寻找不同类别之间的最优分类面,反映的是异类数据之间的差异。
而生成模型学得是各个类别y,和各自的特征x(即可看成学得多个模型),做预测时是判断新数据和已知类别中的哪个最为接近,进而确定新数据的类别,生成模型能够反映同类数据本身的相似度。
由于生产模型学习的是特征x和类别y的联合分布,所以相较于判别模型更为复杂。当建模过程中存在隐变量是,判别模型就无能为力了,而此时生成模型依然能够发挥作用。高斯混合模型(隐变量是类别)和今天的笔者要介绍的主题模型(隐变量是主题)就是属于含有隐变量的生成模型。
主题模型简介
主题模型的核心思想是——一篇文章中的每个词语都是经历以下两个步骤之后生成而来:
-
- 一篇文章以一定概率选择了某个主题,
- 2 .然后并从这个主题中以一定概率选择某个词语。
如下图所示:
:比如某一篇文档 d,它的主题分布如右方红色柱状图所示。这篇文档最有可能是一篇体育,新闻类型的文档。
: 而在某一主题下,它的词语分布如左方蓝色柱状图所示。这个主题应该属于政治类型的主题。
所以主题模型本质上想说一篇文章是如何诞生的:
1.首先选择好文章的主题 ,
2 .然后选择好符合主题的词语组合一下。
有没有发现主题模型的简单粗暴,它行文时并没有考虑词语之间的衔接,语法是否通顺等。其实主题模型依旧是一个词袋模型,并没有考虑语序,语法,语义等高级特征。不过并不妨碍它能够带给我们很多惊喜。
下图是LDA原论文中截图,这里定义了4个主题"Art ,Budgets,Children,Education",
从文章的颜色分布直接可以清晰的判断出绿色的词最多,所以此文章最大的主题应该是:Budgets。其中的大部分词都是从Budgets 这个主题中选择出来的。所以这篇文章可能在讲诉:和预算有关的事情。文章确实讲诉了某基金逐步拨款资助一些青年艺术家。主题模型威力就在于它能很便捷的就帮我们挖掘出一篇文章的主题。
说了这么多了,那下面我们如何得到,如上图所示的信息——(1) 每个主题的词语分布,以及(2)每篇文章的主题分布呢,下面进入实战部分。
LDA 主题模型实战
载入数据
这里笔者采用的今日头条之前一个文本分类的数据,就是一些政治,娱乐,财经新闻之类的文本,需要注意的是"政治,娱乐,财经",就是所谓的主题。同时进行文本分词等预处理等操作。
from gensim.models import LdaModel
import pandas as pd
from gensim.corpora import Dictionary
import jieba
with open("toutiao_cat_data.txt","r",encoding="utf-8") as f:
data = []
for line in f.readlines():
line = line.strip()
line = ','.join(line.split("_!_")[3:])
data.append(jieba.lcut(line))
数据样式如下图所示,即文本分词后的l列表,从数据可以看出,都是些娱乐,政治,体育新闻文本。
文本向量化
LDA采用的是词袋模型,所以将每一条新闻文本,转化为词袋(BOW ——Bag of words)向量,这里笔者过滤掉一些频率过高的词。
dictionary = corpora.Dictionary(data)
dictionary.filter_n_most_frequent(200)
corpus = [dictionary.doc2bow(text) for text in data ]
模型训练
将向量化之后的文本喂给LDA模型,设定好主题的个数(LDA需要指定主题的个数),这里笔者设定了10个主题,运行下方代码就可以开始训练了。笔者实验下来感觉gensim的LDA还是有点慢。
lda = LdaModel(corpus=corpus, id2word=dictionary, num_topics=10)
获取主题词分布
打印出10个主题的词语分布中,排名前20的主题词,实际使用LDA时,我们必须看到各个主题词的分布才能大致了解,某个主题到底是什么。如下图所示:
第5个主题(id = 4)的主题词是"勇士,骑士,世界杯"等,应该是和体育相关。
第10个主题(id =9)的主题词是"上市,股票,黄金"等,应该和经济相关。
topic_list=lda.print_topics(20)
print(topic_list)
获取某一篇文档的主题分布
下方代码是将一篇新的文档的词袋向量,喂给LDA模型让模型输出新文档的主题分布,如下图所示:我们把骑士和猛龙的季后赛半决赛新闻的文本丢给刚刚训练好的主题模型,模型输出:
此文本主题组成中第五个主题(体育相关)占据0.85。
也验证了模型给出主题分布是应该是合理的。
print(data[44])
test_doc=data[44]
doc_bow = dictionary.doc2bow(test_doc) #文档转换成bow
doc_lda = lda[doc_bow]
doc_lda
结语
至此,我们学会了如何通过训练一个主题模型,拿到获取各主题的主题词分布以及如何获取某一篇文档的主题分布。今天的介绍,笔者并没有涉及主题模型内部一些复杂的数学知识,比如Drichlet 分布,共轭分布,吉布斯采样等。这些复杂的数学知识我也只是略懂一二,还达不到说明白的地步,所以也就不提了,感兴趣的同学可以去看参考文献中作者的原文和网上的一些资料。此文章的主要目的想让大家了解主题模型的思想,以及如何使用gensim训练属于你自己的主题模型。
参考文献:
http://www.jmlr.org/papers/volume3/blei03a/blei03a.pdf
https://www.cnblogs.com/Harriett-Lin/p/9621107.html
https://www.cnblogs.com/jhcelue/p/7148935.html