『本文转自:https://wdxtub.com/2017/05/03/lda-guide/』
LDA 作为文本分析中非常有用的算法,无论是在学术界还是工业界都已被广泛运用。本文是写给自己的 LDA 理解指南。
更新历史
- 2017.05.03: 完成初稿
关于 LDA 算法,网上的资料不胜枚举,除了 wiki,我最推荐 《 LDA 漫游指南》。那么为什么我还要自己写一篇呢?一是加深理解,二是给出我在工作中应用 LDA 的一些思考。
基础知识
我们首先需要知道的是,LDA 是一种无监督机器学习技术,用来识别大规模文档集或语料库中潜在隐藏的主题信息。具体是怎么识别主题的呢?LDA 中最小单位是词,并假定每个词是由一个潜在隐藏的主题中抽取出来的。
当然,本文不会涉及具体的推导(用 mathjax 敲这些公式太痛苦了)。我们用上帝视角来还原整个过程:
- 拿到一篇文章,文章是由『词』组成的
- 因为开了上帝视角,我们能够一眼看出每个『词』所属的『主题』
- 又因为开了上帝视角,我们在知道了每个『词』所属的『主题』之后,就可以判断出这篇文章所对应的『主题』了。
那么 LDA 在这里做了什么?其实就是通过概率和计算,帮我们开了这么个上帝视角。如果对具体的推导感兴趣,可以参阅最后的链接。
应用场景
因为每个文章会被『划归』到某个『主题』中,所以我们可以:
- 相似文档发现,具体到产品中可以是『相关新闻』『类似文章』
- 自动打标签,具体步骤为:分词 - 词性标注 - 去掉副词、介词 - LDA 训练 - 获取主题相关词,这些相关词即为标签
- 新闻个性化推荐,具体步骤为:用 LDA 得到文章 Topic - 用 LR 进行点击预测 - 推荐同 Topic 最可能点击(且未点击)的新闻。另一种可能的方式是(不需要 LR):记录用户的点击偏好(比如最常看哪类 topic) - 推荐这个 topic 中 topK 的文章(这个方法更加简答)
主题打分
因为 LDA 生成的主题是没有排序的,所以我们可以把显著的、有特色的主题排到前面,而将不明意义的主题往后面排。
注:这个在客服行业中非常有用,因为有时候会需要从大量的客服日志中提取出通用的 FAQ 问题并建立知识库,如果有这么一个排序,就可以减少人工评判的工作量。
算法的核心思路是当前 topic 的概率分本与垃圾分布的距离。如果你跟我一样用 gensim 这个 python 包的话,那么下面这几个函数需要重点留意:
get_document_topics(bow, minimum_probability=None, minimum_phi_value=None, per_word_topics=False) Return topic distribution for the given document bow, as a list of (topic_id, topic_probability) 2-tuples. Ignore topics with very low probability (below minimum_probability). If per_word_topics is True, it also returns a list of topics, sorted in descending order of most likely topics for that word. It also returns a list of word_ids and each words corresponding topics’ phi_values, multiplied by feature length (i.e, word count) get_term_topics(word_id, minimum_probability=None) Returns most likely topics for a particular word in vocab. get_topic_terms(topicid, topn=10) Return a list of (word_id, probability) 2-tuples for the most probable words in topic topicid. Only return 2-tuples for the topn most probable words (ignore the rest). |
这里我们需要计算两个距离:
- topic -> doc 距离。主要看文章分布是不是过于平均
- topic -> word 距离。主要看关键词排序是不是过于平均
topic -> doc 距离
我们先由前面的 get_document_topics
获取到每个 document 对应 topic,然后转换成每个 topic 对应的 document。因为每个 document 对应到 topic 是有一个概率的,我们需要归一化一下,这里举个例子就清楚了。
# 假设 topic A 中只有四篇文章 doc1 - 属于 topic A 的概率是 0.9 doc2 - 属于 topic A 的概率是 0.8 doc3 - 属于 topic A 的概率是 0.7 doc4 - 属于 topic A 的概率是 0.6 # 那么 topic A -> doc 的概率分布向量经过归一化后是 # 这里的 3 = 0.9 + 0.8 + 0.7 + 0.6,保证这个向量每个元素相加最后等于 1 即可 [0.9/3, 0.8/3, 0.7/3, 0.6/3] # 我们需要跟下面这个背景噪音向量进行比较 # 这里 4 是文章的数目 [1/4, 1/4, 1/4, 1/4] |
然后我们只要计算这两个向量之间的距离即可,各类距离的计算方法可以看这里,KL divergence, Cosine, 皮尔逊相关度之类的都可以,距离越大,主题越有特色。
topic -> word 距离
我们先由 get_topic_terms
获取 topic -> word 的概率分布,然后我们计算出词向量,具体我们还是看例子
# 假设 Topic A 有 4 个关键词(可以自己设置,这里只是一个例子) word1 0.30 word2 0.25 word3 0.25 word4 0.20 # 转化成向量比之前的要简单 [0.3, 0.25, 0.25, 0.2] # 我们需要跟下面这个背景噪音向量进行比较 # 这里 4 是该 topic 下词的数目 [1/4, 1/4, 1/4, 1/4] |
然后我们只要计算这两个向量之间的距离即可,各类距离的计算方法可以看这里,KL divergence, Cosine, 皮尔逊相关度之类的都可以,距离越大,主题越有特色。(和前面一样的只是复制粘贴一下)。
最终得分是一个加权的排序,我们的公式是
这里的 a 和 b 可以根据需要自己调整。
写在最后
抛开原理不谈,其实 LDA 的具体应用更多是在给出一个排序的依据,无论是相似还是推荐,本质都是排序(只是排序的标准不同),而在这个排序的过程中所给出的隐含 topic,如果可以加以利用,就能得到意想不到的效果。