主题建模
在文本挖掘中,我们经常收集一些文档集合,例如博客文章或新闻文章,我们希望将其分成自然组,以便我们可以分别理解它们。主题建模是对这些文档进行无监督分类的一种方法,类似于对数字数据进行聚类,即使我们不确定要查找什么,也可以找到自然的项目组。
潜在狄利克雷分配(LDA)是拟合主题模型特别流行的方法。它将每个文档视为主题的混合体,并将每个主题看作是单词的混合体。这允许文档在内容方面相互“重叠”,而不是分离成离散的组,以反映自然语言的典型用法。
结合主题建模的文本分析流程图。topicmodels包采用Document-Term Matrix作为输入,并生成一个可以通过tidytext进行处理的模型,以便可以使用dplyr和ggplot2对其进行处理和可视化。
如图所示,我们可以使用整齐的文本原理来处理主题建模,这与我们在本书中使用的相同的整洁工具集一致。在本章中,我们将学习如何使用topicmodels包中的LDA对象,特别是整理这些模型,以便可以使用ggplot2和dplyr进行操作。我们还将探索几本丛书的丛集示例,其中我们可以看到一个主题模型“学习”,根据文本内容来区分这四本书。
潜在狄利克雷分配
潜在Dirichlet分配是主题建模中最常用的算法之一。没有深入模型背后的数学,我们可以理解它是由两个原则指导的。
每个文档都是主题的混合体。我们设想每个文档可能包含来自几个主题的文字,特别是比例。例如,在双主题模型中,我们可以说“文档1是90%的主题A和10%的主题B,而文档2是30%的主题A和70%的主题B.”
每个主题都是词汇的混合。例如,我们可以想象一个美国新闻的两个主题模型,一个话题是“政治”,一个是“娱乐”。政治话题中最常见的词语可能是“总统”,“国会”和“政府“,而娱乐主题可以由诸如”电影“,”电视“和”演员“之类的词组成。重要的是,话题可以在话题之间共享; 像“预算”这样的词可能同时出现在两者中。
LDA是一种同时估计这两种情况的数学方法:查找与每个主题相关的单词混合,同时确定描述每个文档的主题混合。这个算法有很多现有的实现,我们将深入探讨其中的一个。
library(topicmodels)data("AssociatedPress")AssociatedPress
: term frequency (tf)
我们可以使用LDA()topicmodels包中的函数设置k = 2来创建两个主题的LDA模型。
实际上几乎所有的主题模型都会使用更大的模型k,但我们很快就会看到,这种分析方法可以扩展到更多的主题。
此函数返回一个包含模型拟合完整细节的对象,例如单词如何与主题关联以及主题如何与文档关联。
# set a seed so that the output of the model is predictableap_lda <- LDA(AssociatedPress,k =2,control =list(seed =1234))ap_lda
拟合模型是“简单部分”:分析的其余部分将涉及使用整理tidytext软件包中的函数来探索和解释模型。
单词主题概率
tidytext包提供了这种方法来提取每个主题的每个词的概率,称为ββ (“测试版”)。
## # A tibble: 20,946 x 3## topic term beta## ## 1 1 aaron 1.69e-12## 2 2 aaron 3.90e- 5## 3 1 abandon 2.65e- 5## 4 2 abandon 3.99e- 5## 5 1 abandoned 1.39e- 4## 6 2 abandoned 5.88e- 5## 7 1 abandoning 2.45e-33## 8 2 abandoning 2.34e- 5## 9 1 abbott 2.13e- 6## 10 2 abbott 2.97e- 5## # ... with 20,936 more rows
每个主题中最常见的术语
这种可视化让我们了解从文章中提取的两个主题。话题1中最常见的词语包括“百分比”,“百万”,“十亿”和“公司”,这表明它可能代表商业或财务新闻。话题2中最常见的包括“总统”,“政府”和“苏维埃”,表示这个话题代表政治新闻。关于每个主题中的单词的一个重要观察是,在这两个主题中,诸如“新”和“人”等一些词语是常见的。与“硬聚类”方法相反,这是话题建模的优势:自然语言中使用的话题可能在话语方面存在一些重叠。
作为替代方案,我们可以认为有条款最大的区别在ββ在主题1和主题2之间。
## # A tibble: 198 x 4## term topic1 topic2 log_ratio## ## 1 administration 0.000431 0.00138 1.68## 2 ago 0.00107 0.000842 -0.339## 3 agreement 0.000671 0.00104 0.630## 4 aid 0.0000476 0.00105 4.46## 5 air 0.00214 0.000297 -2.85## 6 american 0.00203 0.00168 -0.270## 7 analysts 0.00109 0.000000578 -10.9## 8 area 0.00137 0.000231 -2.57## 9 army 0.000262 0.00105 2.00## 10 asked 0.000189 0.00156 3.05## # ... with 188 more rows
图显示了这两个主题之间差异最大的词。
图β中差异最大的词β 在主题2和主题1之间
我们可以看到,话题2中更常见的词包括“民主”和“共和党”等政党,以及“dukakis”和“gorbachev”等政治家的名字。主题1的特点是“日元”和“美元”等货币以及“指数”,“价格”和“利率”等金融术语。这有助于确认算法确定的两个主题是政治和财务新闻。
文档 - 主题概率
除了将每个主题评估为单词混合之外,LDA还将每个文档建模为混合主题。我们可以检查每个文档的每个主题概率,称为γγ(“伽玛”),其matrix = "gamma"论点是tidy()。
## # A tibble: 4,492 x 3## document topic gamma## ## 1 1 1 0.248## 2 2 1 0.362## 3 3 1 0.527## 4 4 1 0.357## 5 5 1 0.181## 6 6 1 0.000588## 7 7 1 0.773## 8 8 1 0.00445## 9 9 1 0.967## 10 10 1 0.147## # ... with 4,482 more rows
这些值中的每一个都是该文档中从该主题生成的单词的估计比例。例如,该模型估计文档1中单词的大约24.8%是从主题1生成的。
我们可以看到,这些文档中的许多文档都是从两个主题的混合中抽取出来的,但文档6几乎完全是从主题2中得出的,其中有一个γγ从主题1接近零。为了检查这个答案,我们可以tidy()使用文档术语矩阵,并检查该文档中最常见的词。
## # A tibble: 287 x 3## document term count## ## 1 6 noriega 16.## 2 6 panama 12.## 3 6 jackson 6.## 4 6 powell 6.## 5 6 administration 5.## 6 6 economic 5.## 7 6 general 5.## 8 6 i 5.## 9 6 panamanian 5.## 10 6 american 4.## # ... with 277 more rows
根据最常见的词汇,这似乎是一篇关于美国政府与巴拿马独裁者曼努埃尔诺列加之间关系的文章,这意味着该算法将其置于专题2(作为政治/国家新闻)是正确的。
例子:伟大的图书馆抢劫
在考察一个统计方法时,在一个非常简单的情况下,你可以知道“正确的答案”。例如,我们可以收集一组明确与四个不同主题相关的文档,然后执行主题建模,以查看该算法是否可以正确区分这四个组。这让我们仔细检查该方法是否有用,并了解它如何以及何时会出错。我们将使用经典文献中的一些数据来尝试。
假设一个破坏者闯入你的书房并撕毁你的四本书:
Charles Dickens的伟大期望
HG Wells 的世界大战
Jules Verne 在海底的两万里
傲慢与偏见简·奥斯汀
我们将使用第3章介绍的gutenbergr包检索这四本书的内容。
titles <- c("Twenty Thousand Leagues under the Sea","The War of the Worlds","Pride and Prejudice","Great Expectations")
作为预处理,我们将它们分成不同的章节,使用tidytext unnest_tokens()将它们分离成单词,然后删除stop_words。我们将每一章都视为一个单独的“文档”,每个章节都有一个像“ Great Expectations_1或”这样的名字Pride and Prejudice_11。(在其他应用程序中,每个文档可能是一篇报纸文章或一篇博客文章)。
## # A tibble: 104,721 x 3## document word n## ## 1 Great Expectations_57 joe 88## 2 Great Expectations_7 joe 70## 3 Great Expectations_17 biddy 63## 4 Great Expectations_27 joe 58## 5 Great Expectations_38 estella 58## 6 Great Expectations_2 joe 56## 7 Great Expectations_23 pocket 53## 8 Great Expectations_15 joe 50## 9 Great Expectations_18 joe 50## 10 The War of the Worlds_16 brother 50## # ... with 104,711 more rows
章节中的LDA
现在我们的数据框word_counts是整齐的,每行一个文档,但topicmodels包需要一个DocumentTermMatrix。如第5.2章所述,我们可以将每行一个令牌转换为DocumentTermMatrix带有tidytext的表cast_dtm()。
chapters_dtm <- word_counts %>% cast_dtm(document, word, n)chapters_dtm
然后,我们可以使用该LDA()功能创建一个四主题模型。在这种情况下,我们知道我们正在寻找四个主题,因为有四本书; 在其他问题中,我们可能需要尝试一些不同的值k。
chapters_lda <- LDA(chapters_dtm,k =4,control =list(seed =1234))chapters_lda
## A LDA_VEM topic model with 4 topics.
就像我们在美联社的数据中所做的那样,我们可以检查每个主题的每个词的概率。
## # A tibble: 72,860 x 3## topic term beta## ## 1 1 joe 5.83e-17## 2 2 joe 3.19e-57## 3 3 joe 4.16e-24## 4 4 joe 1.45e- 2## 5 1 biddy 7.85e-27## 6 2 biddy 4.67e-69## 7 3 biddy 2.26e-46## 8 4 biddy 4.77e- 3## 9 1 estella 3.83e- 6## 10 2 estella 5.32e-65## # ... with 72,850 more rows
这已将模型转换为每行一个主题的单行格式。对于每个组合,该模型计算该术语从该主题生成的概率。例如,术语“joe”从主题1,2或3产生几乎为零的概率,但它占主题4的1.45%。
我们可以使用dplyr top_n()来查找每个主题中的前5个术语。
top_terms <- chapter_topics %>% group_by(topic) %>% top_n(5, beta) %>% ungroup() %>% arrange(topic, -beta)top_terms
## # A tibble: 20 x 3## topic term beta## ## 1 1 elizabeth 0.0141## 2 1 darcy 0.00881## 3 1 miss 0.00871## 4 1 bennet 0.00695## 5 1 jane 0.00650## 6 2 captain 0.0155## 7 2 nautilus 0.0131## 8 2 sea 0.00885## 9 2 nemo 0.00871## 10 2 ned 0.00803## 11 3 people 0.00680## 12 3 martians 0.00651## 13 3 time 0.00535## 14 3 black 0.00528## 15 3 night 0.00448## 16 4 joe 0.0145## 17 4 time 0.00685## 18 4 pip 0.00682## 19 4 looked 0.00637## 20 4 miss 0.00623
这种整齐的输出很适合ggplot2可视化
每个主题中最常见的术语
按文档分类
本分析中的每个文档都代表一个章节。因此,我们可能想知道哪些主题与每个文档相关联。
## # A tibble: 772 x 3## document topic gamma## ## 1 Great Expectations_57 1 0.0000135## 2 Great Expectations_7 1 0.0000147## 3 Great Expectations_17 1 0.0000212## 4 Great Expectations_27 1 0.0000192## 5 Great Expectations_38 1 0.354## 6 Great Expectations_2 1 0.0000172## 7 Great Expectations_23 1 0.551## 8 Great Expectations_15 1 0.0168## 9 Great Expectations_18 1 0.0000127## 10 The War of the Worlds_16 1 0.0000108## # ... with 762 more rows
这些值中的每一个都是该文档中从该主题生成的单词的估计比例。例如,该模型估计,Great Expectations_57文档中的每个单词只有来自主题1(“傲慢与偏见”)的概率为0.00135%。
现在我们有了这些话题概率,我们可以看到我们的无监督学习在区分四本书方面做得如何。我们希望书中的章节大部分(或完全)都是从相应的主题中产生的。
首先,我们将文档名称重新分为标题和章节,之后我们可以将每个文档的每个主题概率可视化。
## # A tibble: 772 x 4## title chapter topic gamma## ## 1 Great Expectations 57 1 0.0000135## 2 Great Expectations 7 1 0.0000147## 3 Great Expectations 17 1 0.0000212## 4 Great Expectations 27 1 0.0000192## 5 Great Expectations 38 1 0.354## 6 Great Expectations 2 1 0.0000172## 7 Great Expectations 23 1 0.551## 8 Great Expectations 15 1 0.0168## 9 Great Expectations 18 1 0.0000127## 10 The War of the Worlds 16 1 0.0000108## # ... with 762 more rows
每本书中每章的伽马概率
我们注意到,几乎所有来自“ 傲慢与偏见”,“世界大战 ”和“ 海底二万里 ”的章节都被认为是一个单独的主题。
chapter_classifications <- chapters_gamma %>% group_by(title, chapter) %>% top_n(1, gamma) %>% ungroup()chapter_classifications
然后,我们可以将每本书与每本书的“共识”主题(其章节中最常见的主题)进行比较,并查看哪些主题经常被错误识别。
通过词汇分配:augment
LDA算法的一个步骤是将每个文档中的每个单词分配给一个主题。文档中的单词越多,则通常gamma该文档 - 主题分类的权重越大()。
我们可能想要采用原始文档字对,并查找每个文档中的哪些字词分配给哪个主题。这是该augment()功能的工作,这也起源于扫帚包装,作为整理模型输出的一种方式。在tidy()检索模型的统计组件时,augment()使用模型将信息添加到原始数据中的每个观察值。
assignments <- augment(chapters_lda,data =chapters_dtm)assignments
这会返回一个整齐的书期计数数据框,但会添加一个额外的列:.topic每个文档中每个术语都分配了一个主题。(augment总是以开头添加额外的列.,以防止覆盖现有的列)。我们可以将此assignments表格与共识书籍标题结合起来,找出哪些词语被错误分类。
## # A tibble: 104,721 x 6## title chapter term count .topic consensus## ## 1 Great Expectations 57 joe 88. 4. Great Expectations## 2 Great Expectations 7 joe 70. 4. Great Expectations## 3 Great Expectations 17 joe 5. 4. Great Expectations## 4 Great Expectations 27 joe 58. 4. Great Expectations## 5 Great Expectations 2 joe 56. 4. Great Expectations## 6 Great Expectations 23 joe 1. 4. Great Expectations## 7 Great Expectations 15 joe 50. 4. Great Expectations## 8 Great Expectations 18 joe 50. 4. Great Expectations## 9 Great Expectations 9 joe 44. 4. Great Expectations## 10 Great Expectations 13 joe 40. 4. Great Expectations## # ... with 104,711 more rows
真正的book(title)和分配给它的book()的组合consensus对于进一步的探索是有用的。例如,我们可以将混淆矩阵可视化,使用dplyr's count()和ggplot2 geom_tile显示一本书中的单词被分配给另一本书的频率。
混淆矩阵显示了LDA分配每本书的单词的位置。这张表的每一行都代表每个单词来自的真实书籍,每一列代表它分配的书籍。
什么是最常见的错误的话?
wrong_words <- assignments %>% filter(title != consensus)wrong_words
## # A tibble: 3,500 x 4## title consensus term n## ## 1 Great Expectations Pride and Prejudice love 44.## 2 Great Expectations Pride and Prejudice sergeant 37.## 3 Great Expectations Pride and Prejudice lady 32.## 4 Great Expectations Pride and Prejudice miss 26.## 5 Great Expectations The War of the Worlds boat 25.## 6 Great Expectations Pride and Prejudice father 19.## 7 Great Expectations The War of the Worlds water 19.## 8 Great Expectations Pride and Prejudice baby 18.## 9 Great Expectations Pride and Prejudice flopson 18.## 10 Great Expectations Pride and Prejudice family 16.## # ... with 3,490 more rows
我们可以看到,即使他们出现在远大的期望中,也常常将一些词语分配给“世界的傲慢与偏见”或“战争”。对于其中的一些词,如“爱”和“女士”,这是因为它们在“傲慢与偏见”中更常见(我们可以通过检查计数来证实)。
另一方面,有一些错误分类的词在他们错误分配的小说中从未出现过。例如,我们可以确认只出现在“flopson” 远大前程,即使它分配给了“傲慢与偏见”集群。
word_counts %>% filter(word == "flopson")
## # A tibble: 3 x 3## document word n## ## 1 Great Expectations_22 flopson 10## 2 Great Expectations_23 flopson 7## 3 Great Expectations_33 flopson 1
替代性LDA实现
LDA()topicmodels包中的函数只是潜在Dirichlet分配算法的一个实现。例如,mallet包(Mimno 2013)实现了一个用于文本分类工具的MALLET Java包的包装,而tidytext包也为该模型输出提供了整理器。
library(mallet)# create a vector with one string per chaptercollapsed
然而,一旦模型创建完成,我们就可以以几乎相同的方式使用本章其余部分描述的函数tidy()和augment()函数。这包括提取每个主题中的单词概率或每个文档中的主题。
可以使用ggplot2以与LDA输出相同的方式探索和可视化模型。
▍关注我们
大数据部落 -中国专业的第三方数据服务提供商,提供定制化的一站式数据挖掘和
QQ: 3025393450
【大数据部落】提供定制化的一站式数据挖掘和统计分析咨询服务
分享最新的大数据资讯,每天学习一点数据分析,让我们一起做有态度的数据人
微信客服号:lico_9e
QQ交流群:186388004
|
请发表评论