作者:汪喵行 R语言中文社区专栏作者
知乎ID:https://www.zhihu.com/people/yhannahwang
前言
在文本挖掘里面,除了情感分析,还有一个很重要的主题就是topic modeling。在生活中,有时候对于文章进行分类时,如果用topic modeling的方法,会比人工分类有效率的多。在topic modeling中,最常用的方法就是LDA(Latent Dirichlet allocation)。简单来说,这种方法可以看成:
1.把每篇文章看作是topic的集合。比如对于一个双话题模型,我们可以认为文章1有90%的可能性是话题1,10%的可能性是话题2;
2.把每个话题(topic)看成是词的集合(bag of words),比如对于话题“政治”,里面会有“政府”,“国会”之类,对于“娱乐”这个话题,里面可能会包括“电影”等等。
我们选取了四本小说:《Twenty Thousand Leagues under the Sea》《The War of the Worlds》 《Pride and Prejudice 》《Great Expectations》,把四本小说的所有章节全部打乱,用这些章节来form 4 个topics。如果聚类的效果好的话,这4个topics应该是对应四本小说的。所以步骤是:
1. 首先把四本小说拆成章节并打乱去掉名字(相当于是unlabeled的凌乱的chapters),文本预处理
2.画四本小说的wordcloud
3.用这些章节去聚类4个topics
4.把所有章节带着小说名称放进4个topics里,看看我们的聚类效果如何
需要用到的packages: gutenbergr / topicmodels / Stringr / dplyr / wordcloud2 / ggplot2 / tidytext/tidyr
先library一遍
library(gutenbergr) # for loading books library(topicmodels) # for modeling topics library(stringr) # deal with string library(dplyr) # do operations on table or dataframe (can do multiple operations using "%>%") library(wordcloud2) # draw word cloud library(ggplot2) # draw pictures library(tidytext) # tidying model objects, extract topic-related probabilities library(tidyr) # tidying model object
1.加载四本书并拆分成章节
#load the four books titles <- c("Twenty Thousand Leagues under the Sea", "The War of the Worlds","Pride and Prejudice", "Great Expectations") books <- gutenberg_works(title %in% titles) %>% gutenberg_download(meta_fields = "title") # split into chapters (with no book titles) chapters <- books %>% group_by(title) %>% mutate(chapter = cumsum(str_detect(text, regex("^chapter ", ignore_ca se = TRUE)))) %>% ungroup() %>% filter(chapter > 0) %>% unite(document, title, chapter)
Output:
可以看出,gutenberg_id代表了书名,text代表了书的内容,每一列都是自然行划分的句子。接下来我们要把它们分割成词语,去掉停用词(a,the之类),因为这些停用词对于我们最后的聚类分析没有意义并且影响结果。然后计算每一个chapter里的每个词语的频数。
# split into words chapters_word <- chapters %>% unnest_tokens(word, text) # remove stop words & find document-word counts wordcount <- chapters_word %>% anti_join(stop_words) %>% count(document, word, sort = TRUE) %>% ungroup()
Output:
其实就是每一个词语在每一个章节里出现的频数啦。
2 绘制四本书的wordcloud
首先把四本小说分清楚,并把每本小说全部分割成词语:
by_chapter1 <- books %>% group_by(title) %>% ungroup() %>% unite(document, title) # split into words by_chapter_word1 <- by_chapter1 %>% unnest_tokens(word, text)
以pride and prejudice为例:
#找出price and prejudice里的所有词 word_countsPAP <- by_chapter_word1[by_chapter_word1$document=='Pride and Prejudice',] #去掉停用词 rept_PAP<- anti_join(word_countsPAP,stop_words) #按词频倒序排序 nPAP <- as.data.frame(table(rept_PAP$word)) nPAP <- nPAP[order(-nPAP$Freq),] #选取频率最高的前100个词 top100PAP <- nPAP[c(1:100),] #画云图 wordcloud2(top100PAP, rotateRatio = 1,color= "random-light",minRotation = -3.3/4, maxRotation = 3.3/4,size = 1.3)
其他三本的绘制云图的方法是一样的,就不放代码了,大家可以照这个例子,自己动手实践下。
3 用以上章节聚类4个Topics
#create a DocumentTermMatrix chapterDTM<- wordcount %>% cast_dtm(document, word, n) # set seed to trace back chapterLDA <- LDA(chapterDTM, k = 4, control = list(seed = 1234))
首先我们要生成一个DTM,因为LDA模型的input需要DTM,然后通过LDA(),根据词频。以章节为单元来生成topics: k=4说明我们要生成4个topics。
Output:
我们可以通过matrix='beta'这个参数来得到每个特定的词属于每一个topic的概率,如下:
(here "beta" represents the probablity that one certain word belongs to one certain topic)
# per-topic-per-word probabilities (beta) _ one-topic-per-term-per-row format chapter_topics <- tidy(chapterLDA, matrix = "beta")
Output:
我们想要得到每一个topic的前五个高频词并绘制出来:
相当于就是把四个topics分开,然后把每个topic下面的对应的所有词按照beta概率进行倒序排列,找到前五个概率(beta)最大的词语。
#find top-5 terms within each topic top_terms <- chapter_topics %>% group_by(topic) %>% top_n(5, beta) %>% ungroup() %>% arrange(topic, -beta)
通过上图可以清晰看出这四个topic分别代表的是哪本小说。通过和上文小说的高频词进行比较,粗略上看,发现我们用unlabelled的章节进行聚类得到的四个topics和四本小说的相关度还是很高的。
4 把小说名字放进去,看看聚类效果
上面我们已经成功用打乱的章节聚类成了四本小说,通过topics的高频词和小说高频词的云图对的对比粗略得到模型结果还不错,但是具体聚类效果如何,可能需要我们把章节重新带着小说名称放进topics,看看被分错的章节多不多。
gamma 不同于beta,gamma这里代表的是每一个章节属于每一个topic的概率:
# check per-document-per-topic probabilities (gamma) chapters_gamma <- tidy(chapterLDA, matrix = "gamma") chapters_gamma <- chapters_gamma %>% separate(document, c("title", "chapter"), sep = "_", convert = TRUE)
Output:
比如第一条,说明Great Expectation的第57章属于topic1的概率就是1.33857e-05.
把章节分回topics里:
chapter_classifications <- chapters_gamma %>% group_by(title, chapter) %>% top_n(1, gamma) %>% ungroup()
那么哪些章节被错分了呢?我们画个图会直观一些:
从图中可以看出,Great Expectation有几章被错误分到了topic1和topic2,我们要具体看一下到底是哪几章被分错了:
#find the misclassified chapters misclassifications <- chapter_classifications %>% inner_join(book_topics, by = "topic") %>% filter(title != consensus)
Output:
可以看出,Great Expectation的23章被错误分到了代表pride and prejudice的那个topic,Great Expectation的第54章被错误分到了代表 The war of the Worlds的topic里。
我们还想知道词被分到的topics的情况,所以把词也按照概率分到topic里面去:
# find which words in each document were assigned to which topic assignws <- augment(chapterLDA, data = chapterDTM) #combine book_topics and table assigntopic <- assignws %>%separate(document, c("title", "chapter"), sep = "_", convert = TRUE) %>% inner_join(book_topics, by = c(".topic" = "topic"))
画出词被分的topic的情况:
同样的,有些本来属于Great Expectation的词,错误分到了代表另外两本小说的topics里。
最后,哪些词是最容易被分错的呢?
#get wrong words misclassified_word <- assigntopic %>% filter(title != consensus) misclassified_word %>% count(title, consensus, term, wt = count) %>% ungroup() %>% arrange(desc(n))
Output:
可以看出,"love","miss"这些词是最容易被分错的,这也很好理解,无论是哪种小说,里面出现love,miss这种词语的可能性确实是很高的。
总结
Topic modeling不仅仅适合话题分类,也适合小说分类,通过clustering的方法,我们可以实现更快地给文本分类。
参考:
Text Mining with R
( https://www.tidytextmining.com/ )
(附)
画图代码:
1.keywords for 4 topics:
top_terms %>% mutate(term = reorder(term, beta)) %>% ggplot(aes(term,beta,fill=factor(topic))) + geom_col(show.legend = TRUE,alpha = 0.6) + labs(title = "Top5 Key words for 4 topics")+ facet_wrap(~ topic, scales = "free") + coord_flip(expand = TRUE)+ theme(axis.text.y = element_text(size=11), axis.text.x = element_text(size=10), panel.grid.major=element_blank(), panel.grid.minor=element_blank(), panel.background = element_rect(fill = "gray95"), panel.border=element_rect(fill="transparent",color="light gray"), plot.title = element_text(lineheight = 610,colour = "black",size = 15))
2.chapter classification for 4 topics:
chapters_gamma %>% mutate(title = reorder(title, gamma * topic)) %>% ggplot(aes(factor(topic),fill=factor(topic), gamma)) + labs(title = "Chapter Classification for 4 Topics")+ theme(axis.text.y = element_text(size=11), axis.text.x = element_text(size=10), panel.grid.major=element_blank(), panel.grid.minor=element_blank(), panel.background = element_rect(fill = "gray95"), panel.border=element_rect(fill="transparent",color="light gray"), plot.title = element_text(lineheight = 610,colour = "black",size = 15))+ geom_col(show.legend = TRUE,alpha = 0.6) + facet_wrap(~ title)
3.words assigned to topics:
ssigntopic %>% count(title, consensus, wt = count) %>% group_by(title) %>% mutate(percent = n/sum(n) ) %>% ggplot(aes(consensus, title, fill = percent)) + geom_tile() + scale_fill_gradient2(high = "dark blue") + theme_minimal() + theme(axis.text.x = element_text(angle = 90, hjust = 1), panel.grid = element_blank()) + labs(x = "Book words assignment", y = "Book words came from", fill = "% of assignments")
公众号后台回复关键字即可学习
回复 爬虫 爬虫三大案例实战
回复 Python 1小时破冰入门
回复 数据挖掘 R语言入门及数据挖掘
回复 人工智能 三个月入门人工智能
回复 数据分析师 数据分析师成长之路
回复 机器学习 机器学习的商业应用
回复 数据科学 数据科学实战
回复 常用算法 常用数据挖掘算法
本文由R语言中文社区 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。
以上所述就是小编给大家介绍的《用LDA在R中聚类四本小说》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 小说精品屋——小说阅读弹幕网站源码,开源中国首发
- 小说精品屋 V1.1 发布,小说阅读弹幕网站
- 小说精品屋 v2.3.0 发布,小说阅读弹幕网站
- 小说精品屋 v2.4.0 发布,小说阅读弹幕网站
- 小说精品屋 - plus v1.1.0 发布,小说阅读门户平台
- 小说精品屋 - plus v2.0.2 发布,小说爬虫/原创网站
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Effective Ruby:改善Ruby程序的48条建议
Peter J. Jones / 杨政权、秦五一、孟樊超 / 机械工业出版社 / 2016-1 / 49
如果你是经验丰富的Rub程序员,本书能帮助你发挥Ruby的全部力量来编写更稳健、高效、可维护和易执行的代码。Peter J.Jones凭借其近十年的Ruby开发经验,总结出48条Ruby的最佳实践、专家建议和捷径,并辅以可执行的代码实例。 Jones在Ruby开发的每个主要领域都给出了实用的建议,从模块、内存到元编程。他对鲜为人知的Ruby方言、怪癖、误区和强力影响代码行为与性能的复杂性的揭......一起来看看 《Effective Ruby:改善Ruby程序的48条建议》 这本书的介绍吧!