社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

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

磐创AI • 1 年前 • 907 次点击  

主题建模是自然语言处理(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
 
907 次点击