Py学习  »  Python

Python主题建模详细教程(附代码示例)

磐创AI • 10 月前 • 391 次点击  

主题建模是自然语言处理(NLP)和文本挖掘中常用的技术,用于提取给定文本的主题。利用主题建模,我们可以扫描大量的非结构化文本以检测关键词、主题和主题。

主题建模是一种无监督的机器学习技术,不需要标记数据进行模型训练。它不应与主题分类混淆,后者是一种监督机器学习技术,需要标记数据进行训练以拟合和学习。

在某些情况下,主题建模可以与主题分类一起使用,首先进行主题建模以检测给定文本中的主题,并将每个记录标记为其对应的主题。然后,使用这些标记的数据来训练分类器并对未知数据执行主题分类。

在本文中,我们将专注于主题建模,涵盖如何通过文本预处理来准备数据,如何使用潜Dirichlet分配(LDA)分配最佳主题数量,如何使用LDA提取主题,以及如何使用pyLDAvis可视化主题。

在阅读本文的同时,我鼓励你查看我的GitHub上的Jupyter笔记本以获取完整的分析和代码。

https://github.com/Idilismiguzel/NLP-with-Python/blob/master/Topic%20Modeling/Disneyland_Reviews_Topic_Modeling_LDA.ipynb

我们有很多事情要涵盖,让我们开始吧!🤓


1.数据

我们将使用可从Kaggle下载的Disneyland评论数据集。它包括巴黎、加利福尼亚和香港迪士尼乐园的42,000条评论和评分。评分列包括评分分数,可用于主题分类,将未知评论分类为积极的、消极的或中性的。这超出了本文的范围,但如果你对主题分类感兴趣,可以查看下面的文章。

https://medium.com/analytics-vidhya/applying-text-classification-using-logistic-regression-a-comparison-between-bow-and-tf-idf-1f1ed1b83640

让我们读取数据并查看前几行。

# Read the datareviews = pd.read_csv('/content/DisneylandReviews.csv', encoding='latin-1')
# Remove missing valuesreviews = reviews.dropna()

让我们仅筛选“评论”和“评分”列。

# Filter only related columns and drop duplicated reviewsreviews = reviews[["Review_Text", "Rating"]]reviews = reviews.drop_duplicates(subset='Review_Text')

让我们使用 seaborn 的 countplot 来打印一个条形图,以了解评论的总体情感。

# Create a bar plot with value countssns.countplot(x='Rating', data=reviews)

2.数据清理和预处理

在开始主题建模之前,我们需要准备文本,执行清理和预处理。这是所有文本挖掘管道中至关重要的一步,最终模型的性能高度取决于它。我们将为此数据集遵循以下步骤:

1.将每个单词小写

2.用它们的较长形式替换缩略词

3.删除特殊字符和不需要的单词

4.通过使用 nltk.WordPunctTokenizer() 分词器从单词或句子字符串中提取标记。

5.通过使用 nltk.stem.WordNetLemmatizer() 词形还原器将每个单词还原为其字典形式,以便将具有相似含义的单词链接到一个单词。

要应用所有列出的步骤,我将使用以下函数。然而,为了增加模块化和便于调试,你可以将每个任务定义为单独的函数。

def text_preprocessing(text):
# Convert words to lower case text = text.lower()
# Expand contractions if True: text = text.split() new_text = [] for word in text: if word in contractions: new_text.append(contractions[word]) else: new_text.append(word) text = " ".join(new_text)
# Format words and remove unwanted characters text = re.sub(r'https?:\/\/.*[\r\n]*', '', text, flags=re.MULTILINE) text = re.sub(r'\, ' ', text) text = re.sub(r'&', '', text) text = re.sub(r'[_"\-;%()|+&=*%.,!?:#$@\[\]/]', ' ', text) text = re.sub(r'
'
, ' ', text)
text = re.sub(r'\'', ' ', text)
# Tokenize each word text = nltk.WordPunctTokenizer().tokenize(text)
# Lemmatize each word text = [nltk.stem.WordNetLemmatizer().lemmatize(token, pos='v') for token in text if len(token)>1]
return text
def to_string(text):    # Convert list to string    text = ' '.join(map(str, text))
return text
# Create a list of review by applying text_preprocessing functionreviews['Review_Clean_List'] = list(map(text_preprocessing, reviews.Review_Text))
# Return to string with to_string functionreviews['Review_Clean'] = list(map(to_string, reviews['Review_Clean_List']))

让我们打印一行随机行以查看新列。

在进行下一步之前,我们需要删除停用词。停用词是语言特定的常见单词(例如英语中的“the”、“a”、“and”、“an”),它们既不增加价值也不改善评论的解释,并且往往会在建模中引入偏见。

我们将从nltk库中加载英语停用词列表,并从我们的语料库中删除这些单词。

由于我们正在删除停用词,我们可能想检查我们的语料库中最常见的单词,并评估我们是否也想删除其中的一些。其中一些单词可能只是重复出现,对意义没有任何贡献。

我们将使用collections库中的Counter来计算单词。

# Import Counter from collections import Counter
# Join all word corpusreview_words = ','.join(list(reviews['Review_Clean'].values))
# Count and find the 30 most frequentCounter = Counter(review_words.split())most_frequent = Counter.most_common(30)
# Bar plot of frequent wordsfig = plt.figure(1, figsize = (20,10))_ = pd.DataFrame(most_frequent, columns=("words","count"))sns.barplot(x = 'words', y = 'count', data = _, palette = 'winter')plt.xticks(rotation=45);

正如预期的那样,前30个最常见的词与迪士尼和公园内容有关,如“公园”、“迪士尼”和“迪士尼乐园”。我们将把这些词添加到停用词列表中以删除它们。你也可以创建一个单独的列表。

# Load the list of stopwordsnltk.download('stopwords')
stopwords_list = stopwords.words('english')stopwords_list.extend(['park', 'disney', 'disneyland'])
reviews['Review_Clean_List'] = [[word for word in line if word not in stopwords_list] for line in reviews['Review_Clean_List']]reviews['Review_Clean'] = list(map(text_as_string, reviews['Review_Clean_List']))
# Join all word corpusreview_words = ','.join(list(reviews['Review_Clean'].values))
# Count and find the 30 most frequentCounter = Counter(review_words.split())most_frequent = Counter.most_common(30)
# Bar plot of frequent wordsfig = plt.figure(1, figsize = (20,10))_ = pd.DataFrame(most_frequent, columns=("words","count"))sns.barplot(x = 'words', y = 'count', data = _, palette = 'winter')plt.xticks(rotation=45);

奖励部分

让我们使用之前创建的review_words生成文本语料库的词云。




    
# Generate the word cloudwordcloud = WordCloud(background_color="white",                      max_words= 200,                      contour_width = 8,                      contour_color = "steelblue",                      collocations=False).generate(review_words)
# Visualize the word cloudfig = plt.figure(1, figsize = (10, 10))plt.axis('off')plt.imshow(wordcloud)plt.show()

3.词袋模型

为了将文本作为机器学习算法的输入,我们需要以数值形式呈现它。词袋模型是一种向量空间模型,表示文档中单词的出现次数。换句话说,词袋将每个评论转换为一个单词计数的集合,而不考虑单词的顺序或含义。

我们将首先使用Gensim的corpora.Dictionary创建字典,然后使用dictionary.doc2bow创建词袋。

# Create Dictionaryid2word = gensim.corpora.Dictionary(reviews['Review_Clean_List'])
# Create Corpus: Term Document Frequencycorpus = [id2word.doc2bow(text) for text in reviews['Review_Clean_List']]

通过创建字典,我们将每个单词映射到一个整数ID(即id2word),然后我们在每个字典上调用doc2bow函数,创建一个(id,频率)元组的列表。

4.确定主题数量

决定主题建模的数量可能很困难。由于我们有上下文的初始知识,因此确定建模的主题数量不会太过离谱。然而,如果此数量太多,则模型可能无法检测到实际上更广泛的主题,如果此数量太少,则主题可能具有大量重叠的单词。因此,我们将使用主题相干性得分。

from gensim.models import CoherenceModel
# Compute coherence scorenumber_of_topics = []coherence_score = []for i in range(1,10): lda_model = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=id2word, iterations=50, num_topics=i) coherence_model_lda = CoherenceModel(model=lda_model, texts=reviews['Review_Clean_List'], dictionary=id2word, coherence='c_v') coherence_lda = coherence_model_lda.get_coherence() number_of_topics.append(i) coherence_score.append(coherence_lda)
# Create a dataframe of coherence score by number of topics topic_coherence = pd.DataFrame({'number_of_topics':number_of_topics, 'coherence_score':coherence_score})
# Print a line plotsns.lineplot(data=topic_coherence, x='number_of_topics', y='coherence_score')

由于使用四个主题得到了非常高的一致性分数(0.3429),而从四个到五个主题并没有明显的提高,因此我们将使用四个主题构建LDA模型。

但是,需要注意的是,我们将一致性超参数定义为coherence='c_v',但也有其他选项,例如'u_mass'、'c_uci'、'c_npmi',最好验证它们。(请查看Gensim文档以获取详细信息。)

https://radimrehurek.com/gensim/models/coherencemodel.html

5.使用LDA进行主题建模

潜在狄利克雷分配(Latent Dirichlet Allocation, LDA)是一种常用的用于主题建模的统计无监督机器学习模型。它假设每个主题由词组成,而每个文档(在我们的情况下是每个评论)由这些词的集合组成。因此,LDA试图找到最能描述每个主题的词,并匹配由这些词表示的评论。

LDA使用狄利克雷分布,这是一种Beta分布的概括,用于对两个或更多结果(K)进行概率分布建模。例如,K = 2是Beta分布的狄利克雷分布的特殊情况。

狄利克雷分布用Dir(α)表示,其中α < 1(对称)表示稀疏性,这正是我们希望用于主题建模的主题和单词的表示方式。

正如下面所示,当α < 1时,我们在各个边角上有圆圈相隔(换句话说是稀疏的),当α > 1时,我们在中心有相互靠近且难以区分的圆圈。你可以将这些圆圈想象成主题。

LDA使用两个狄利克雷分布,其中:

K是主题数量。M表示文档数量。N表示给定文档中的单词数量。Dir(alpha)是每个文档的主题分布的狄利克雷分布。Dir(beta)是每个主题的单词分布的狄利克雷分布。

然后,它使用每个单词位置的多项式分布:

选择文档i中第j个单词的主题;z_{i,j} 选择特定单词的单词;w_{i,j}

如果我们将所有的部分组合在一起,我们得到下面的公式,它描述了具有两个狄利克雷分布后跟多项式分布的文档的概率。

让我们看看如何在Python中使用gensim的ldaModel执行LDA模型。

# Define the number of topics 


    
n_topics = 4
# Run the LDA modellda_model = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=id2word, num_topics=n_topics, random_state=100, update_every=1, chunksize=10, passes=10, alpha='symmetric', iterations=100, per_word_topics=True)

让我们来探讨一下在每个话题中出现的单词及其相对权重。

for idx, topic in lda_model.print_topics(-1):    print("Topic: {} Word: {}".format(idx, topic))

我们可以看到,一个主题与排队和等待有关;下一个主题与参观、停留和食物有关;另一个主题与酒店、门票和村庄有关;最后一个主题与魔法、爱情和强调巴黎和佛罗里达的表演有关。

6.用 pyLDAvis 可视化

pyLDAvis 是一个交互式的基于 Web 的可视化工具,用于可视化主题模型。你可以使用 pip install pyldavis 在 Python 中轻松安装,并使用 enable_notebook() 在 Python 笔记本上运行可视化。

# Import and enable notebook to run visualizationimport pyLDAvis.gensim_models


    
pyLDAvis.enable_notebook()
vis = pyLDAvis.gensim_models.prepare(lda_model, corpus, dictionary=lda_model.id2word)vis

在左侧,我们可以看到每个主题在主题距离图上表示为气泡,这个图是多维缩放在 x 和 y 轴上,如果我们单击一个主题,可视化会自动调整到该特定主题。气泡之间的距离表示主题之间的语义距离,如果气泡重叠,这意味着有很多共同的词。在我们的例子中,主题很好地分离且不重叠。此外,主题气泡的面积表示每个主题的覆盖范围,主题 1 占评价的约 50%,而其他主题则几乎平均分享。

右侧的可视化显示每个主题的前 30 个最相关单词,蓝色的条形图表示单词在所有评价中的出现次数,红色的条形图表示单词在所选主题中的出现次数。在顶部,你可以看到一个滑块来调整相关性指标 λ(其中 0 ≤ λ ≤ 1),λ = 1 调整可视化以显示每个主题中最有可能出现的单词,而 λ = 0 则调整为显示所选主题专有的单词。

让我们来看看第二个主题

主题3:

最后一个是主题 4

结论

在本文中,我们探讨了如何从文本数据中检测主题和关键词,以便无需扫描整个文本就能理解内容。

我们介绍了如何应用预处理,包括清理文本、词形还原和去除停用词和最常见的词,以准备数据进行机器学习。我

们还创建了一个词云,帮助我们可视化整个内容。

为了找到迪士尼乐园评论数据集的主题,我们使用了潜在狄利克雷分配(LDA),这是一种概率主题建模方法,假设主题可以表示为文本语料库中单词的分布。每个文档(在我们的案例中为评论)可以展示多个主题,且比例不同。选择具有最高比例的主题作为该文档的主题。我们使用一致性分数定义了主题的数量,并使用pyLDAvis可视化了我们的主题和关键词。

LDA是一种相对简单的主题建模技术,而且由于有了pyLDAvis,你可以向不熟悉技术范围的人展示结果。可视化还有助于描述工作原理,使主题模型更易于理解和解释。

虽然我们只涵盖了LDA技术,但还有许多其他可用于主题建模的技术。例如,潜在语义分析(LSA)、非负矩阵分解、Word2vec等。如果你对此感兴趣,我强烈推荐探索这些方法,它们根据使用情况具有不同的优势和劣势。

参考引用

1.Disneyland Reviews data set from Kaggle. License: CC0: Public Domain


推荐一个人工智能AI公众号,我们每日更新AI行业最新动态,机器学习干货文章,深度学习原创博客,深度学习实战项目,国外最新论文翻译等,为大家分享AI行业的新鲜事,希望大家喜欢。点击下方卡片关注我们吧~ 




✄-----------------------------------------------

看到这里,说明你喜欢这篇文章,请点击「在看」或顺手「转发」「点赞」。

欢迎微信搜索「panchuangxx」,添加小编磐小小仙微信,每日朋友圈更新一篇高质量推文(无广告),为您提供更多精彩内容。


▼     扫描二维码添加小编  ▼  ▼  

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/155922
 
391 次点击