毕业论文案例-LDA主题模型实现文本聚类

news2025/7/10 18:29:46

本文结构框架

  • 引言
  • LDA主题模型的预备知识
    • (1)多项式分布 Multinomial Distribution
    • (2)狄利克雷分布 Dirichlet Distribution
    • (3)共轭分布 Conjugate Distribution
    • (4)吉普斯采样 Gibbs Sampling
  • LDA主题模型的代码过程
    • (1)文本预处理
    • (2)建模和可视化
    • (3)模型优化
        • A、困惑度(perplexity)
        • B、一致性(coherence)
        • C、可视化聚类效果
        • D、距离度量
        • E、主题方差
  • LDA主题模型的优点和不足

引言

这是一篇以我毕业论文为背景的博客。由于对数据分析非常感兴趣,所以选择这个主题。在论文的撰写中,我参考了大量相关的CSDN博客。

时光匆匆,在毕业之际,我愿意分享论文过程的体会和心得,给各位兄弟姐妹们做个参考。

(以下内容知网查重过,勿搬运)

LDA主题模型的预备知识

LDA主题模型本质是文本聚类算法,属于文档生成模型(利用样本的相似性)。它常用于对文本数据的主题挖掘中,比如对用户评论的挖掘,人才招聘需求信息的挖掘等。它是NLP中一个常用的算法。

(1)多项式分布 Multinomial Distribution

多项式分布是二项分布的推广。最常见的二项分布比如抛硬币的实验,实验结果只有两个,即正面和反面,且每个结果发生概率为1/2。现在我们假设掷骰子的实验,6个面分别对应6个不同的点数,每个点数出现的概率都是1/6,这就是一个典型的多项分布。但这是很理想的情况,现在我们把它推广至n个情况,且每个面出现的概率是不确定,我们就可以认为各结果出现的概率服从一定的分布,概率密度函数如下:
P { X 1 = n 1 , X 2 = n 2 , … , X r = n r } = n ! n 1 ! n 2 ! … n r ! P 1 n 1 P 2 n 2 … P r n r P \lbrace X_1=n_1,X_2=n_2, \ldots ,X_r=n_r \rbrace ={n! \over n_1!n_2! \ldots n_r!} P{ ^{n_1}_1 }P{ ^{n_2}_2 } \ldots P{ ^{n_r}_r } P{X1=n1,X2=n2,,Xr=nr}=n1!n2!nr!n!P1n1P2n2Prnr
其中, n 1 + n 2 + … + n r = n n_1+n_2+ \ldots+n_r=n n1+n2++nr=n
P 1 + P 2 + … + P r = 1 P_1+P_2+ \ldots+P_r=1 P1+P2++Pr=1
本文假定主题分布和词分布均服从与多项式分布。这是由于:一篇文章都有一定数量的主题,且能够以一定的概率去选择某个主题。换句话说,在全部的主题数中(文章包含的和未包含的),文章所对应的主题概率大部分都为0,只有有限个主题的概率不为0,我们将每篇文章对应的主题概率看作一行,所有文章排列组合起来,可以得到一个巨大的稀疏矩阵,这与多项式的分布比较相似。所以,我们用多项式分布来拟合主题分布和词分布。

(2)狄利克雷分布 Dirichlet Distribution

狄利克雷分布是贝塔分布推广至多变量的情形,其概率密度函数如下:
在这里插入图片描述

其中,向量α是狄利克雷分布的参数;B(α)表示 Dirichlet分布的归一化常数。

(3)共轭分布 Conjugate Distribution

共轭分布式贝叶斯统计中的一个常用概念,当后验分布的概率密度函数与先验分布的概率密度函数具有相同的形式时,我们称它们为一组共轭分布。比如贝塔分布和二项分布是一组共轭分布,本文所用的狄利克雷分布和多项式分布是一组共轭先验分布。

(4)吉普斯采样 Gibbs Sampling

吉布斯采样是一种简单且广泛适用的马尔可夫链蒙特卡洛(MCMC)算法,可以看作是Metropolis-Hastings算法的一个特例。吉布斯采样适用于联合分布未明确知道或难以直接抽样但每个变量的条件分布是已知的并且很容易(或者至少更容易)从中抽样的情况。具体来说,它交替的固定某一维度,然后通过其他维度的值来抽样该维度的值。本文的LDA主题模型是一个文档生成模型,它就是通过吉普斯采样来生成的。

LDA主题模型的代码过程

所用样本是跟研究主题相关的新闻评论。故以下处理均是针对中文文本进行的。原始数据文本如下:
在这里插入图片描述

(1)文本预处理

这一部分较常规,包括结巴库分词,添加停用词。

#这里定义停用词列表
def stopwordslist(filepath):
    stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()]
    return stopwords

# 对句子进行分词
def seg_sentence(sentence):
    sentence = re.sub(u'[0-9\.]+', u'', sentence)
    
    jb.add_word('今年')		# 这里是加入用户自定义的词来补充jieba词典。
    jb.add_word('成为')	    # 想要删除的词语就先把它加上然后放进停用词表
    jb.add_word('通过')
    jb.add_word('我们')
    jb.add_word('自己')
    jb.add_word('以来')
    jb.add_word('没有')
    jb.add_word('天津')
    jb.add_word('电商')
    jb.add_word('西安')
    
    sentence_seged = jb.cut(sentence.strip())
    stopwords = pd.read_csv("./stopwords.txt",index_col=False,quoting=3,sep=" ",names=['stopword'],encoding='UTF-8')
    stopwords = stopwordslist('./stopwords.txt')  # 这里加载停用词的路径
    outstr = ''
    for word in sentence_seged:
        if word not in stopwords and word.__len__()>1:
            if word != '\t':
                outstr += word
                outstr += " "
    return outstr

#这里要注意编码问题 inputs即是读入原文本,outputs即是新建一个文本,然后将处理好的文本放入
inputs = open('./text.txt','r',encoding='gb18030')


outputs = open('./text03.txt','w',encoding='gb18030')
for line in inputs:
    line_seg = seg_sentence(line)  # 这里的返回值是字符串
    outputs.write(line_seg + '\n')
outputs.close()
inputs.close()

于是,预处理完毕后的文本就被存放在outputs文本里,下一步操作直接导入outputs即可。预处理后的文本如下:
在这里插入图片描述

(2)建模和可视化

建立LDA主题模型的代码有很多,这里给出本文所用的:

#这里先导入常用库
from gensim import corpora
from gensim.models import LdaModel
from gensim.corpora import Dictionary
import codecs

train = []

fp=codecs.open(r'F:\Desktop\comments_chuli\text03.txt','r',encoding='gb18030')

data=fp.read()
fp.close()

'''
for line in data: 
    if line != '':
        line = line.split(" ")
        train.append([w for w in line])
'''
#以下几行将train列表的每个元素都生成一个列表 形成列表嵌套
train0=data.split(" ")
train=[]
for i in range(len(train0)):
    train1=[]
    train1.append(train0[i])
    train.append(train1)


dictionary = corpora.Dictionary(train)
dictionary.filter_extremes(no_below=2, no_above=0.1)

corpus = [dictionary.doc2bow(text) for text in train]

lda = LdaModel(corpus=corpus, id2word=dictionary, num_topics=10, passes=50)
#corpus是词袋,dictionary是词典
# num_topics:主题数目
# passes:训练伦次
# num_words:每个主题下输出的term的数目
#corpus指语料词典

#以下为模型的输出结果,即是每个主题下的20个特征词
#可以适当注释,节省运行时间

for topic in lda.print_topics(num_words = 20):
    termNumber = topic[0]
    print(topic[0], ':', sep='')
    listOfTerms = topic[1].split('+')
    for term in listOfTerms:
        listItems = term.split('*')
        print('  ', listItems[1], '(', listItems[0], ')', sep='')
  
    
#--------------以下是代码可视化部分------------------------------

#将可视化结果保存到lda001的网页上
import gensim
from gensim import models
import pyLDAvis.gensim_models
pyLDAvis.enable_notebook()
def lda_vis():
    #dictionary = gensim.corpora.Dictionary.load('lda.dict')
    #corpus = gensim.corpora.MmCorpus('lda.mm')
    #lda = models.ldamodel.LdaModel.load('lda.lda')
    vis = pyLDAvis.gensim_models.prepare(lda, corpus, dictionary)
    pyLDAvis.save_html(vis, r'F:\Desktop\comments_chuli\lda001.html')
    return 0
 
 
if __name__ == '__main__':
    lda_vis()

根据模型运行出的结果,即每个主题下的20个词语,能够倒推出来它是属于哪一类的主题,从而实现主题的挖掘。这里我截取主题数为5时,模型运行结果如下,下图是每个主题下的特征词,括号里是各特征词的权重:
在这里插入图片描述
这里需要注意的是:

(1)由于LDA模型是一个文档生成模型,需要不断取样生成主题和词语,并多次重复,建模过程比较复杂,运算时间比较长。因此,根据情况对部分代码加上注释减少它的运行时间;

(2)特别需要注意的是,用词袋模型处理数据类型一定是一个列表嵌套,对应的,上文中的train是一个列表嵌套。(这里大坑,我花了不少时间)

(3)模型优化

LDA主题模型本质上是一个文本聚类模型,并且它与K-means聚类算法一样,是需要我们手动输入聚类个数的。

当聚类个数过多,可能出现过度拟合的现象;

而聚类个数过少,可能使得不同的主题聚为一类,聚类效果不明显;

因此,对于聚类算法来说,确定合适的主题数至关重要。

LDA主题模型中,对于主题数的选取有以下五种:

A、困惑度(perplexity)

由Ble提出,主要内容是对于训练后的模型构建似然函数并求其最大值,值越大表明提取主题的质量最优,此时的困惑度最小,它可以理解为训练后的模型对于一篇文档C有哪些主题是不确定的,所以困惑度的大小与模型质量成反比

B、一致性(coherence)

由LauJH(2010)提出的,它是一种基于主题相关性的定量评价,主要内容是一致性的大小与模型质量成正比

C、可视化聚类效果

类似Excel中的气泡图,气泡的大小代表主题在文档出现的频率(权重),气泡之间的距离代表主题间的相关性。因此,气泡的间隔越远,说明模型的聚类效果越好。

D、距离度量

由曹娟(2008)提出来的,利用主题间的相似度来选择最优LDA模型的方法,通过计算主题向量的余弦距离和KL距离来计算主题的相似度,主题平均相似度最小时,模型效果最好。

E、主题方差

由关鹏(2016)提出的,用主题方差衡量主题空间的整体差异性和稳定性,当方差越大时,主题间的区分度越大,说明模型的效果越好。

本文采用前三种,以下是相关的代码:

#-------------计算困惑度-------------------------------------
import codecs
import gensim
from gensim import corpora, models
import matplotlib.pyplot as plt
import matplotlib
from nltk.tokenize import RegexpTokenizer
from nltk.stem.porter import PorterStemmer



fp = codecs.open('./text03.txt','r',encoding='gb18030')
data=fp.read()
fp.close()

#以下几行将train列表的每个元素都生成一个列表 形成列表嵌套
train0=data.split(" ")
train=[]
for i in range(len(train0)):
    train1=[]
    train1.append(train0[i])
    train.append(train1)

dictionary = corpora.Dictionary(train)  # 构建 document-term matrix
corpus = [dictionary.doc2bow(text) for text in train]
Lda = gensim.models.ldamodel.LdaModel
    
def perplexity(num_topics):
    ldamodel = Lda(corpus, num_topics=num_topics, id2word = dictionary, passes=50)  #passes为迭代次数,次数越多越精准
    print(ldamodel.print_topics(num_topics=num_topics, num_words=7))  #num_words为每个主题下的词语数量
    print(ldamodel.log_perplexity(corpus))
    return ldamodel.log_perplexity(corpus)
 
# 绘制困惑度折线图
x = range(1,10)  #主题范围数量
y = [perplexity(i) for i in x]
plt.plot(x, y)
plt.xlabel('主题数目')
plt.ylabel('困惑度大小')
plt.rcParams['font.sans-serif']=['SimHei']
matplotlib.rcParams['axes.unicode_minus']=False
plt.title('主题-困惑度变化情况')
plt.show()

#----------------计算一致性-------------------------------
#计算coherence

from gensim.models.coherencemodel import CoherenceModel
 
def coherence(num_topics):
    ldamodel = Lda(corpus, num_topics=num_topics, id2word = dictionary, passes=30,random_state = 1)
    #print(ldamodel.print_topics(num_topics=num_topics, num_words=7))
    ldacm = CoherenceModel(model=ldamodel, texts=train, dictionary=dictionary, coherence='c_v')
    #print(ldacm.get_coherence())
    return ldacm.get_coherence()

x = range(1,10)
# z = [perplexity(i) for i in x]  #如果想用困惑度就选这个
y = [coherence(i) for i in x]
plt.plot(x, y)
plt.xlabel('主题数目')
plt.ylabel('一致性大小')
plt.rcParams['font.sans-serif']=['SimHei']
matplotlib.rcParams['axes.unicode_minus']=False
plt.title('主题-一致性变化情况')
plt.show()

困惑度和模型质量成反比,一致性与模型质量成正比。困惑度和一致性具体的含义可查阅相关论文,这里只给出代码的实现方法。

根据困惑度和一致性可以初步确定主题数目的范围,再辅以可视化聚类效果,能够确定合适的主题数目.

以下是可视化聚类的效果图:
分别是K=10,5,4
Alt
在这里插入图片描述
在这里插入图片描述
从上述三幅图对比可得,当主题数为10时,主题线条过细,模型过度拟合;当主题数为5时,主题2、3仍有部分相交;而当主题数为4是,各个主题相隔较远,聚类效果明显,且在主题无相交的条件下,模型的困惑度达到最小。故本文应设定主题数为4。

LDA主题模型的优点和不足

LDA主题模型的优点是相对于传统的主题聚类算法来说。比如PLSA算法,它认为文档-主题、主题-词语的分布均是一个确定值。通俗的讲,首先以一定的概率选择某个主题,再在这个主题下以一定的概率选择某个词语,不断的重复这两步,直至生成整篇文章。

而LDA主题模型则被称为是贝叶斯版本下的PLSA。LDA模型采用了贝叶斯学派的思想,把一切参数都看作随机变量,都服从一定的概率先验分布。因此,它为主题分布和词分布都加上了两个狄利克雷的先验分布。

LDA主题模型的结构流程图具体可参考网上,很常见,这里就不再给出。

由于LDA模型采用了贝叶斯学派的思想,在小样本以及可靠性统计的情况下,运行结果相比于经典统计学派更具优势;

但是LDA模型也有它自身的局限性:比如说进行文本向量化的时候,用的是词袋模型。词袋模型只考虑了词数,未考虑词序;比如说用矩阵来描述词语,当文档和词语增加,会形成一个巨大的稀疏矩阵,可能造成维度灾难等;没有考虑一些更先进的方法,如用上下文的语义来预测下文的词语等。

需要本文数据和代码,可在本文评论区留言或者私信我。

希望对各位兄弟姐妹们有所帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot整合webSocket(看完即入门)

webSocket1、什么是webSocket?2、webSocket可以用来做什么?3、webSocket协议4、服务端WebSocket操作类5、客户端1、什么是webSocket? WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单&am…

100天精通Python(可视化篇)——第77天:数据可视化入门基础大全(万字总结+含常用图表动图展示)

文章目录1. 什么是数据可视化?2. 为什么会用数据可视化?3. 数据可视化的好处?4. 如何使用数据可视化?5. Python数据可视化常用工具1)Matplotlib绘图2)Seaborn绘图3)Bokeh绘图6. 常用图表介绍及其…

【Windows】六种正确清理C盘的方法,解决你的红色烦恼

如何正确的清理C盘前言清理方法1. 利用Windows自己附带的磁盘清理工具2. 开启自动清理3. 通过“配置存储感知或立即运行”来清理4. 管理C盘中的程序5. 系统文件夹转移6. 将C盘现有内容转移到别的盘参考链接前言 Windows操作系统一般是安装在磁盘驱动器的C盘中,运行…

D435i相机的标定及VINS-Fusion config文件修改

引言 当我们想使用D435i相机去跑VINS-Fusion时,如果不把标定过的相机信息写入config文件中就运行,这样运动轨迹会抖动十分严重,里程计很容易漂。接下来将介绍如何标定D435i相机,并设置VINS-Fusion的config文件。 一 标定前的准备…

k8s中job与cronjob使用详解

一、前言 job,顾名思义就是任务,job的概念在很多框架中都有,而且实际业务场景中也使用非常广泛,比如大家熟悉的hadoop,客户端可以向集群提交一个job,然后集群根据一定的调度策略来处理这个job; k8s中的job,主要用于批量处理的业务场景,比如像那种短暂的一次性任务(每个…

java 代码样式为什么需要事务,讲述Spring5事务几种方式 认识API

首先 在上一文java Spring5 搭建操作数据库事务环境中 我们搭建了一个事务的业务场景 然后 打开项目 我们继续 先看到数据库表 看好两个人的余额 然后 来到senvice层下的transfAccoSenvice 将里面的 transferAccounts方法 更改如下 //转账方法 public void transferAccounts…

Vue的路由配置(Vue2和Vue3的路由配置)

系列文章目录 Tips:使用Vue3开发项目已经有一段时间了,关于Vue2的路由是如何一步一步搭建的都快要忘记了,今天写着篇文章主要就是回顾一下,在Vue2和Vue3中我们是如何一步一步的配置路由的。 提示:最好的进步就是有闲暇…

如何知道你的推荐流每条数据是通过哪种策略召回?

大家好,我是空空star,本篇带你了解下C站PC首页推荐流召回策略。 文章目录前言一、utm_medium二、召回策略1.user_follow_bbs:用户关注社区的红包帖子召回2.user_follow:用户关注召回3.top_blink:热门blink召回4.hot&am…

滚动条样式修改

前言 浏览器中的滚动条样式大家一定都不陌生,其样式并不好康。可能很多小伙伴还不知道,这个东东的样式也可以修改(仅支持部分现代浏览器),本次就来带大家用 CSS 修改一下它的样式。 一、认识滚动条 首先我们先来简单…

(一)卷积神经网络模型之——LeNet

目录LeNet模型参数介绍该网络特点关于C3与S2之间的连接关于最后的输出层子采样参考LeNet LeNet是一个用来识别手写数字的最经典的卷积神经网络,是Yann LeCun在1998年设计并提出的。Lenet的网络结构规模较小,但包含了卷积层、池化层、全连接层&#xff0…

【前端进阶】-TypeScript高级类型 | 泛型约束、泛型接口、泛型工具类型

前言 博主主页👉🏻蜡笔雏田学代码 专栏链接👉🏻【TypeScript专栏】 前两篇文章讲解了TypeScript的一些高级类型 详细内容请阅读如下:🔽 【前端进阶】-TypeScript高级类型 | 交叉类型、索引签名类型、映射类…

直接在前端调用 GPT-3 API

〇、效果展示 一、代码&#xff1a;ask.html app.js ask.html&#xff08;内嵌css&#xff09; <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>ChatGPT Web Example</title><style>/* 你的 CSS 代码 */bod…

CSS 轻松实现‘毛玻璃’效果

毛玻璃1. backdrop-filt 属性2. filter 属性3. backdrop-filter && filter4. 参考资料1. backdrop-filt 属性 通过为元素添加backdrop-filter:blur(模糊值) 这个 CSS 属性&#xff0c;元素所在的区域后方包括后方的其他元素会模糊或颜色有所偏移&#xff0c;元素本身包…

深拷贝的五种实现方式

一、什么是深拷贝和浅拷贝 浅拷贝是创建一个新对象&#xff0c;这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型&#xff0c;拷贝的就是基本类型的值&#xff0c;如果属性是引用类型&#xff0c;拷贝的就是指向内存的地址 &#xff0c;所以如果其中一个对象改变…

npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。

为了解决npm命令无法正常运行的问题 接上个博客 安装完新版node后使用npm命令会出现以下错误 大致意思就是识别不了npm命令是干啥的 解决方案: 1.首先确定是不是软件没有获得管理员权限运行,右键程序选择管理员权限运行 2.如果管理员权限运行后依然出现错误,检查node的配置…

React 框架

文章目录一、React 框架简介二、配置环境三、组件&#xff08;Component&#xff09;四、Component 组件的组合与交互一、React 框架简介 介绍 CS 与 BS结合&#xff1a;像 React&#xff0c;Vue 此类框架&#xff0c;转移了部分服务器的功能到客户端。将CS 和 BS 加以结合。客…

java简历项目经验案例(java简历项目经验怎么写)

如何描述项目经验-seo简历项目经验怎么&#xff1f;seo简历项目经验怎么写 写自己从事过的什么项目。写具体什么模块。如果没有就写自己能达到什么水平&#xff0c;能做出什么模块。 什么叫项目经验&#xff1f;什么叫项目经验?简历中的项目经验可以写些什么? 项目经验与工作…

flex布局之flex-direction

一、flex布局的原理 1,flex是”flexible Box”的缩写&#xff0c;意为”弹性布局”&#xff1b; 2.当我们为父盒子设为flex布局以后&#xff0c;子元素的float、clear和vertical-align属性将会失效。 言而简之&#xff1a;flex布局原理就是通过给父盒子添加flex属性&#xff0…

VUE项目部署

前端项目的部署 1.1 开发完的vue的项目 首先运行 以下命令 对项目进行打包 npm run build1.2 安装nginx服务器 ​ nginx是一款轻量级的Web服务器、反向代理服务器&#xff0c;由于它的内存占用少&#xff0c;启动极快&#xff0c;高并发能力强&#xff0c;在互联网项目中广泛…

若依RuoYi-Vue前后端项目启动流程

1.git找到RuoYi-Vue RuoYi-Vue: &#x1f389; 基于SpringBoot&#xff0c;Spring Security&#xff0c;JWT&#xff0c;Vue & Element 的前后端分离权限管理系统&#xff0c;同时提供了 Vue3 的版本 2.本地创建文件夹&#xff0c;cmd进入该文件夹下并进行克隆项目 git cl…