介绍
随着文章、电子邮件和简历等文档形式的大量数据,人们对如何组织、汇总、访问和解释这些数据的需求越来越大。
这就是主题建模发挥作用的地方。
主题建模是一种无监督学习技术,可以挖掘给定文档集合中的潜在“主题”。它能够根据主题对文档进行分组或划分,这使它成为企业非常宝贵的资产。主题建模存在于许多应用中,如推荐系统和搜索引擎。
主题建模最流行的方法之一是潜狄利克雷分配(LDA)。
在这里,我们提供了LDA的快速概述,并演示了如何使用Python执行它
LDA
执行LDA需要使用概率模型捕获给定文档集合中的信息。
该技术基于以下2个假设:
- 每个文档包含多个主题
- 每一个主题都由单词组成
LDA用主题概率表示文档,用单词概率表示主题。
由于LDA背后的算法,使用该主题建模方法需要大量计算。
幸运的是,有了Python的NLP模块(我们将很快介绍),所有繁重的工作都为你完成了。任何给定文档集合的实际LDA模型都可以用最少的代码构建!
既然如此,我们可以坐下来参考Stack Overflow,让我们的程序为我们做所有的工作,对吗?
嗯,不完全是。
挑战
尽管由于Python强大的模块,LDA中的计算不难执行,但在进行LDA时,用户需要做出一些关键决定。
首先,给定的数据集应该有多少个主题?这是一个用户定义的参数。如果指定的主题数量不适合,则从文档中获取主题的任何努力都将失败。
此外,在构建LDA模型之后,你将得到每个主题的单词概率。请记住,LDA是一种无监督的学习技术,因此用户的任务是根据与之相关的单词来决定每个主题代表什么。即使LDA模型是稳健的,如果其结果不可破译,它也没有用。
个案研究
为了巩固对这个主题建模方法的理解,使用真实数据应用它是有益的。
LDA可用于汇总大量数据。可以利用这个主题建模方法来识别文档中陈述的要点,而不是解析每个文档中的每个细节。
让我们使用LDA从评论集合中挖掘主题。
对于这个演示,我们使用了一个亚马逊食品评论数据集(无版权),可以在这里访问。这是一个庞大的数据集,因此我们将研究范围限制在前100000条记录。
这是数据集的预览。
import pandas as pd
# load dataset
df = pd.read_csv('Reviews.csv', usecols=['Id', 'Text']).iloc[:100000,:]
df.head()
1.预处理
当然,在执行LDA之前,需要对评论进行预处理,以便分析成功。
首先,我们使用Gensim模块对评论分词。此外,我们将所有字符小写并删除任何标点符号。
import gensim
from gensim.parsing.preprocessing import preprocess_string, strip_punctuation
def tokenize(text: str) -> str:
"""Tokenize given text"""
CUSTOM_FILTERS = [lambda x: x.lower(), strip_punctuation]
text = preprocess_string(text, CUSTOM_FILTERS)
return text
# tokenize reviews
doc_token = df['Text'].apply(lambda x: tokenize(x))
接下来,我们将bigram添加到分词后的文档中。
# add bigrams to the corpus
bigram = gensim.models.Phrases(doc_token, threshold=100, min_count=5)
doc_bigram = [bigram[doc_token[i]] for i in range(len(doc_token))]
最后,我们移除所有出现的停用词或短词,并使用NLTK模块对剩余的单词执行词形还原。
import nltk
from nltk import WordNetLemmatizer
from nltk.corpus import stopwords
# list of stop words
stopwords = stopwords.words('english')
# create lemmatizer object
lem = WordNetLemmatizer()
# lemmatize words if they are not stop words or short words
doc_list = []
for sent in doc_bigram:
new_doc = [lem.lemmatize(word) for word in sent if word not in stopwords and len(word)>3]
doc_list.append(new_doc)
要查看预处理后数据是如何修改的,我们可以将其添加到数据帧中。
# preview of dataset
df['Text (Preprocessed)'] = doc_list
df.head()
2.创建文档单词矩阵和字典
与大多数NLP模型一样,LDA模型需要文档单词矩阵作为输入。它还需要一本语料库中所有单词的字典。
from gensim import corpora
# create dictionary
dictionary = corpora.Dictionary(doc_list)
# create document term matrix
bow = [dictionary.doc2bow(text) for text in doc_list]
3.确定主题数量
在构建LDA模型之前,我们需要确定食品评论集合中的主题数量。
这可能很难确定,因为任何给定的文档集合中都没有多少主题的经验法则。因此,有不同的方法可以用来确定这个数字。
第一种方法是创建具有不同主题数量的多个LDA模型,并查看哪一个最容易解释。另一种方法是利用领域知识来确定该值。
在这种情况下,我们将使用一致性评分指标作为食物评论集合中有多少主题的指标。连贯性得分本质上是衡量分配给每个主题的单词在语义价值方面有多相似的一个指标。分数越高越好。
让我们计算具有2到10个主题的LDA模型的一致性得分,看看哪个主题的数量导致了最高的一致性分数。
from gensim.models import LdaModel
from gensim.models.coherencemodel import CoherenceModel
import numpy as np
best_num = float('NaN')
best_score = 0
# compute the coherence scores for each number of topics
for i in range(2,11):
# create lda model with i topics
lda = LdaModel(corpus=bow, num_topics=i, id2word=dictionary, random_state=42)
# obtain the coherence score
coherence_model = CoherenceModel(model=lda, texts=doc_list, dictionary=dictionary, coherence='c_v')
coherence_score = np.round(coherence_model.get_coherence(),2)
if coherence_score > best_score:
best_num = i
best_score = coherence_score
print(f'The coherence score is highest ({best_score}) with {best_num} topics.')
根据一致性得分指标,亚马逊食品评论中应该有9个基本主题。
4.建立LDA模型
既然我们已经确定了最佳主题数量,我们就可以构建LDA模型了。
# build the lda model
lda_model = gensim.models.ldamodel.LdaModel(corpus=bow,
id2word=dictionary,
num_topics=9,
random_state=42)
5.解释结果
一旦建立了模型,我们就可以根据概率得分来判断哪些单词对哪个主题的亲和力最强。
我们可以使用与每个主题相关的单词来解释主题并找出它们所代表的内容:
主题0:茶相关产品的评论
主题1:美味小吃点评
主题2:对产品质量的总体正面评价
主题3:含糖饮料的评论
主题4:咖啡相关产品的评论
主题5:产品口味概述
主题6:宠物食品评论
主题7:关于产品包装的审查
主题8:巧克力相关产品的评论
就像这样,我们能够以9个主题的形式总结10万份食品评论中的数据。这些主题提供了客户谈论的内容的大致概念。
我们还可以使用该模型来确定每个文档中的主题混合。
# obtain topic distributions for each document
topic_dist = lda_model[bow]
# store distributions ina list
dist = []
for t in topic_dist:
dist.append(t)
# add list to the data frame
df['Topic Distribution'] = topic_dist
# dataset preview
df[['Text', 'Topic Distribution']].head()
让我们以第一篇食物评论为例。
评论:“我买了几款Vitality罐装狗粮产品,发现它们的质量都很好。产品看起来更像炖肉,而不是加工肉,闻起来更香。我的拉布拉多很挑剔,她比大多数人更喜欢这种产品。”
6.可视化结果(可选)
虽然我们可以用我们已经提供的信息解释文档中的每个主题,但可视化LDA的结果将增强后续分析。
pyLDAvis模块允许我们通过交互式可视化更好地解释LDA模型的结果。
import pyLDAvis
import pyLDAvis.gensim_models as gensim_models
# visualize LDA model results
pyLDAvis.enable_notebook()
gensim_models.prepare(lda_model, dictionary=dictionary, corpus=bow)
交互式可视化以绘图(左)和水平条形图(右)的形式出现。
情节中的每个气泡代表一个主题。气泡的大小表示包含该主题的评论的比例,较大的气泡对应较高的比例。气泡之间的距离表示主题之间的相似性;距离越短,主题越相似。
条形图中的条形图表示每个单词的词频。蓝色条显示文档集合中的总体单词频率,而红色条显示所选主题的单词频率。
当然,在进行LDA时,创建这样的工具并不是一个强制性步骤,但任何漂亮实用的视觉辅助工具都是一个值得欢迎的补充,因为它可以更容易地从研究中获得结果并将其展示给其他人。
毕竟,谁不喜欢好的视觉效果?
结论
到目前为止,你已经大致了解了LDA的功能以及如何使用Python强大的模块执行LDA。
感谢阅读!
参考引用
J. McAuley and J. Leskovec. From amateurs to connoisseurs: modeling the evolution of user expertise through online reviews. WWW, 2013.
Blei, David & Ng, Andrew & Jordan, Michael. (2001). Latent Dirichlet Allocation. The Journal of Machine Learning Research. 3. 601–608.