LDA(Latent Dirichlet Allocation)的原理和代码实现

LDA的概要简述

LDA(Latent Dirichlet Allocation)主题模型是一种文档生成模型,也是一种非监督机器学习技术,基于贝叶斯模型的一种方法。它认为一篇文档是有多个主题的,而每个主题又对应着不同的词。在LDA的理论当中一篇文档的主题构造过程如下所示,首先是以一定的概率选择文档当中的某个词,然后再在这个词下以一定的概率选出某一个主题,这样就生成了这篇文档的第一个主题。不断重复这个过程,就生成了指定的K个主题。(如果大家仅仅只是了解的话就不用看详细生成过程了,反正个人一句话理解就是LDA可以帮助你生成一篇文章的主题,该主题能够代表这篇文章,后文部分有代码和例子,自己拷过去运行即可)

 

                                                                                     LDA图模型的表示

根据上图,我们可以详细讨论LDA的工作过程,LDA假设文档主题的先验分布是Dirichlet分布,即对于任一文档d,其主题分布θd为:

其中α为其分布的超参数,它是一个K维向量,K是实现指定的主题个数。由于在LDA当中主题对应的词的分布是Dirichlet分布,也就是对于任意一个主题k,它的词分布βk为:

η为分布的超参数,是一个V维向量,V代表词汇个数。根据词汇当中的任意一篇文档d当中的第n个词,可以通过θd得到主题编号Zdn的分布,同时还可以得到词Wdn的分布,就这样不断的循环下去直至完成整个语料库。

最后我们可以得到每个文档对应的K维向量,这K维向量当中的每一个值代表该文档与对应主题的相关程度,因此可以通过比较向量之间的相似度来替代文档之间的相似度。向量相似度计算有很多方法,其中包括皮尔逊相关系数(Pearson product-moment correlation coefficient)、欧几里德距离(Euclidean distance)等,我们采用最简单也常用的夹角余弦来度量两个向量之间的相似度,余弦值越大,两个向量就越接近,则两个文本就越相似。计算公式如下。

 

除此之外我们还可以使用熵权法来计算每个主题对于文本的权值大小,一般来说若某个主题的信息熵越小,表明其提供的信息量就越多,因此在该主题集合当中所起的作用也就越大,权值也会越大。 

LDA的代码实现

实现代码见下,需要在同一文件下建立一个名称为“D1_wiki”的txt文件,编码为utf8,里面每行记录着一篇文档经过分词过后形成的单词组合,我已经上传到网盘了,大家可以进行下载(链接:https://pan.baidu.com/s/1cLgy543fFozu47YPaMq5MA 提取码:3g2g )。在本文当中我使用的是一组维基百科概念在页面的正文部分的文本作为一篇文档的组成,一共有351个概念,关于维基百科概念如何获取页面的正文部分请看我之前写的一篇“通过Python获取维基百科中概念词条的维基信息”一文。获取到正文后我们还需要对正文部分的语句进行分词,由于英文维基百科的访问不需要翻墙(中文暂时需要),因此分词对象我们选择英文维基百科的文本进行,有关分词以及概念的处理我个人强烈推荐使用工具TagMe,TagMe目前是科学界最好的实体链接工具之一,具有非常好的性能,特别是在注释短文本时(即由几十个术语组成的那些)。简单来讲这个工具主要解决一段文本当中的概念标注问题,有关它的使用也在我的一篇“关于在python中TagMe包的使用说明以及测试”一文中有详细介绍,里面会带大家从注册到使用的一整套流程。

# coding=utf-8
# Author:Zhou Yang


from sklearn.feature_extraction.text import CountVectorizer

if __name__ == "__main__":

     # 存储读取语料 一行语料为一个文档 文档当中词语词之间用空格分隔
     corpus = []
     for line in open('D1_wiki.txt', 'r', encoding="utf8").readlines():
          # print line
          corpus.append(line.strip())
          # print(corpus)
     topic_num = 20




     # 将文本中的词语转换为词频矩阵 矩阵元素a[i][j] 表示j词在i类文本下的词频
     vectorizer = CountVectorizer()
     print(vectorizer)

     X = vectorizer.fit_transform(corpus)
     analyze = vectorizer.build_analyzer()
     weight = X.toarray()

     print(len(weight))
     print(weight[:35, :35])

     # LDA算法
     print('LDA:')
     import numpy as np
     import lda
     #import lda.datasets

     np.set_printoptions(suppress=True)

     model = lda.LDA(n_topics=topic_num, n_iter=500, random_state=1)
     model.fit(np.asarray(weight))  # model.fit_transform(X) is also available
     topic_word = model.topic_word_  # model.components_ also works

     print("------")
     print(model)
     print("------")

     # print(topic_word.shape)

     word = vectorizer.get_feature_names()

     label = []
     # 主题-词语(Topic-Word)分布
     for n in range(topic_num):
          # topic_most_pr = topic_word[n]
          topic_most_pr = topic_word[n].argmax()
          label.append(topic_most_pr)
          print("topic: {} word: {}".format(n, word[topic_most_pr]))



     # 文档-主题(Document-Topic)分布
     doc_topic = model.doc_topic_
     print("type(doc_topic): {}".format(type(doc_topic)))
     print("shape: {}".format(doc_topic.shape))

     # print(doc_topic)

     # 选择对应词的大小值
     for i in doc_topic:
          print(list(i), end=",")

实验过程我设置的主题词个数为20,迭代次数为500。其实主题词的设置要看你的需求,但是如果你想要更加科学的设置的话请参阅《 Griffiths TL, Steyvers M (2004) Finding scientific topics. Proc Nat Acad Sci USA 101(Suppl 1):5228–
5235》这篇文章,关于主题个数的选择我还推荐一篇武大的博士写的一篇文章《Zhang N, Wang J, He K, et al. Mining and clustering service goals for RESTful service discovery[J]. Knowledge and Information Systems, 2018: 1-32.》,不过文章的下载需要翻墙和注册spring等操作,同时也要支付一定的价格才能访问,我导师已经把这篇文章搞到手给我研究了(因为他也是武大的博士),我在这里截图显示文章所讲的部分的精髓。

运行上面的代码得到的结果有两部分,一个是确定的20个主题,另外是351组维度为20的向量,每个向量当中的值代表20个主题当中作为该文档的主题相关程序大小。我在这里列举出这20个主题供大家参考。

topic: 0 word: british_empire
topic: 1 word: greenhouse_gas
topic: 2 word: economics
topic: 3 word: law
topic: 4 word: physics
topic: 5 word: biology
topic: 6 word: mathematics
topic: 7 word: united_kingdom
topic: 8 word: aeronautics
topic: 9 word: chemistry
topic: 10 word: geology
topic: 11 word: état
topic: 12 word: research
topic: 13 word: earth
topic: 14 word: electricity_generation
topic: 15 word: germany
topic: 16 word: united_states
topic: 17 word: earth
topic: 18 word: mexico
topic: 19 word: magazine

由于维基百科的部分概念是由多个词组成,因此这种情况我其中的空格用下划线代替。

计算还得到351组20维度的向量我就不列了,有兴趣自己跑一下代码就出来了!

如果你还想了解更多有关短文本主题提取的文章我还建议你去看2018年最新的一篇文章《Topic Memory Networks》,这篇论文由腾讯 AI Lab 主导,与香港中文大学合作完成。是主题模型与文本分类在神经网络框架下的一次结合,作为主题模型与深度学习联合训练的一个早期的探索,能够很自然地被扩展到很多深度学习任务的上。我在这上面研究了一段时间,感觉还是挺有意思的,对于当今各种短文本消息例如微博什么的主题提取还是很有用的。

参考文献

Blei D M, Ng A Y, Jordan M I. Latent dirichlet allocation[J]. Journal of machine Learning research, 2003, 3(Jan): 993-1022.

Talukdar P P, Cohen W W. Crowdsourced comprehension: predicting prerequisite structure in wikipedia[C]//Proceedings of the Seventh Workshop on Building Educational Applications Using NLP. Association for Computational Linguistics, 2012: 307-315.

Zhang N, Wang J, He K, et al. Mining and clustering service goals for RESTful service discovery[J]. Knowledge and Information Systems, 2018: 1-32.

Griffiths T L, Steyvers M. Finding scientific topics[J]. Proceedings of the National academy of Sciences, 2004, 101(suppl 1): 5228-5235.

Zeng J, Li J, Song Y, et al. Topic memory networks for short text classification[J]. arXiv preprint arXiv:1809.03664, 2018.

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值