主题模型(Topic Model)与LDA算法

2023-11-06

  • Topic Model

主题模型(Topic Model)是以非监督学习的方式对文档的隐含语义结构(latent semantic structure)进行聚类(clustering)的统计模型

主题模型认为在词(word)与文档(document)之间没有直接的联系,它们应当还有一个维度将它们串联起来,主题模型将这个维度称为主题(topic)。每个文档都应该对应着一个或多个的主题,而每个主题都会有对应的词分布,通过主题,就可以得到每个文档的词分布。依据这一原理,就可以得到主题模型的一个核心公式:

p(w_{i}|d_{j})=\sum_{k=1}^{K}p(w_{i}|t_{k})\times p(t_{k}|d_{j})

在一个已知的数据集中,每个词和文档对应的p(w_{i}|d_{j})都是已知的。而主题模型就是根据这个已知的信息,通过计算p(w_{i}|t_{k})p(t_{k}|d_{j})的值,从而得到主题的词分布和文档的主题分布信息。而要得到这个分布信息,现在常用的方法就是LSA(LSI)和LDA。其中LSA主要是采用SVD的方法进行暴力破解,而LDA则是通过贝叶斯学派的方法对分布信息进行拟合。

  • LDA算法

隐含狄利克雷分布(Latent Dirichlet Allocation, LDA)是由David Blei等人在2003年提出的,该方法的理论基础是贝叶斯理论。LDA根据词的共现信息的分析,拟合出词-文档-主题的分布,进而将词、文本都映射到一个语义空间中。

LDA算法假设文档中主题的先验分布和主题中词的先验分布都服从狄利克雷分布。在贝叶斯学派看来,先验分布+数据(似然)=后验分布。我们通过对已有数据集的统计,就可以得到每篇文档中主题的多项式分布和每个主题对应词的多项式分布。然后就可以根据贝叶斯学派的方法,通过先验的狄利克雷分布和观测数据得到的多项式分布,得到一组Dirichlet-multi共轭,并据此来推断文档中主题的后验分布,也就是我们最后需要的结果。那么具体的LDA模型应当如何进行求解,其中一种主流的方法就是吉布斯采样。结合吉布斯采样的LDA模型训练过程一般如下:

  1. 随机初始化,对语料中每篇文档中的每个词w,随机地赋予一个topic编号z。
  2. 重新扫描语料库,对每个词w按照吉布斯采样公式重新采样它的topic,在语料中进行更新。
  3. 重复以上语料库的重新采样过程直到吉布斯采样收敛。
  4. 统计语料库的topic-word共现频率矩阵,该矩阵就是LDA的模型。

经过以上的步骤,就得到一个训练好的LDA模型,接下来就可以按照一定的方式针对新文档的topic进行预估,具体步骤如下:

  1. 随机初始化,对当前文档中的每个词w,随机地赋予一个topic编号z。
  2. 重新扫描当前文档,按照吉布斯采样公式,重新采样它的topic。
  3. 重复以上过程直到吉布斯采样收敛。
  4. 统计文档中的topic分布即为预估结果。

具体的LDA理论可以参考rickjin写的LDA数学八卦:http://www.52nlp.cn/lda-math-%E6%B1%87%E6%80%BB-lda%E6%95%B0%E5%AD%A6%E5%85%AB%E5%8D%A6

  • 提取文本关键词

通过上面的LSI或LDA算法,我们得到了文档对主题的分布和主题对词的分布,接下来就是要利用这些信息来对关键词进行抽取。在我们得到主题对词的分布后,也据此得到词对主题的分布。接下来,就可以通过这个分布信息计算文档与词的相似性,继而得到文档最相似的词列表,最后就可以得到文档的关键词。

TF-IDF实现文本关键词提取的基础上,实现一个完整的主题模型,分别实现LSI、LDA算法,根据传入参数model进行选择。几个参数如下:

  • doc_list:是前面数据集加载方法的返回结果。
  • keyword_num:同上,为关键词数量。
  • model:本主题模型的具体算法,分别可以传入LSI、LDA,默认为LSI。
  • num_topics为主题模型的主题数量。

LSI和LDA的训练是根据现有的数据集生成文档-主题分布矩阵和主题-词分布矩阵,Gensim中有实现好的训练方法,直接调用即可。

from gensim import corpora, models

# 主题模型
class TopicModel(object):
    # 三个传入参数:处理后的数据集,关键词数量,具体模型(LSI、LDA),主题数量
    def __init__(self, doc_list, keyword_num, model='LSI', num_topics=4):
        # 使用gensim的接口,将文本转为向量化表示
        # 先构建词空间
        self.dictionary = corpora.Dictionary(doc_list)
        # 使用BOW模型向量化
        corpus = [self.dictionary.doc2bow(doc) for doc in doc_list]
        # 对每个词,根据tf-idf进行加权,得到加权后的向量表示
        self.tfidf_model = models.TfidfModel(corpus)
        self.corpus_tfidf = self.tfidf_model[corpus]

        self.keyword_num = keyword_num
        self.num_topics = num_topics
        # 选择加载的模型
        if model == 'LSI':
            self.model = self.train_lsi()
        else:
            self.model = self.train_lda()

        # 得到数据集的主题-词分布
        word_dic = self.word_dictionary(doc_list)
        self.wordtopic_dic = self.get_wordtopic(word_dic)

    def train_lsi(self):
        lsi = models.LsiModel(self.corpus_tfidf, id2word=self.dictionary, num_topics=self.num_topics)
        return lsi

    def train_lda(self):
        lda = models.LdaModel(self.corpus_tfidf, id2word=self.dictionary, num_topics=self.num_topics)
        return lda

    def get_wordtopic(self, word_dic):
        wordtopic_dic = {}

        for word in word_dic:
            single_list = [word]
            wordcorpus = self.tfidf_model[self.dictionary.doc2bow(single_list)]
            wordtopic = self.model[wordcorpus]
            wordtopic_dic[word] = wordtopic
        return wordtopic_dic

    # 计算词的分布和文档的分布的相似度,取相似度最高的keyword_num个词作为关键词
    def get_simword(self, word_list):
        sentcorpus = self.tfidf_model[self.dictionary.doc2bow(word_list)]
        senttopic = self.model[sentcorpus]

        # 余弦相似度计算
        def calsim(l1, l2):
            a, b, c = 0.0, 0.0, 0.0
            for t1, t2 in zip(l1, l2):
                x1 = t1[1]
                x2 = t2[1]
                a += x1 * x1
                b += x1 * x1
                c += x2 * x2
            sim = a / math.sqrt(b * c) if not (b * c) == 0.0 else 0.0
            return sim

        # 计算输入文本和每个词的主题分布相似度
        sim_dic = {}
        for k, v in self.wordtopic_dic.items():
            if k not in word_list:
                continue
            sim = calsim(v, senttopic)
            sim_dic[k] = sim

        for k, v in sorted(sim_dic.items(), key=functools.cmp_to_key(cmp), reverse=True)[:self.keyword_num]:
            print(k + "/ ", end='')
        print()

    @staticmethod
    # 词空间构建方法和向量化方法,在没有gensim接口时的一般处理方法
    def word_dictionary(doc_list):
        dictionary = []
        for doc in doc_list:
            dictionary.extend(doc)

        dictionary = list(set(dictionary))
        return dictionary

    def doc2bowvec(self, word_list):
        vec_list = [1 if word in word_list else 0 for word in self.dictionary]
        return vec_list

统一算法调用接口:

def topic_extract(word_list, model, pos=False, keyword_num=10):
    doc_list = load_data(pos)
    topic_model = TopicModel(doc_list, keyword_num, model=model)
    topic_model.get_simword(word_list)

对目标文本进行关键词提取:

if __name__ == '__main__':
    text =  '费尔南多·托雷斯(Fernando Jose Torres Sanz),1984年3月20日出生于西班牙马德里,' + \
            '西班牙足球运动员,司职前锋,效力于日本职业足球甲级联赛鸟栖砂岩足球俱乐部。' + \
            '托雷斯2001出道于马德里竞技,2007年加盟英超利物浦,2011年转会切尔西,' + \
            '期间帮助球队夺得了2012年欧洲冠军联赛冠军,其后以租借的形式加盟AC米兰,' + \
            '2014年12月,托雷斯宣布回归马德里竞技。2018年7月,托雷斯宣布加盟日本鸟栖砂岩足球俱乐部。' + \
            '2004年欧洲杯,托雷斯首次代表国家队参加国际大赛,2008年和2012年跟随西班牙队两度夺得欧洲杯冠军,' + \
            '2010年随队夺得世界杯冠军,其个人在2008年荣膺欧洲杯决赛MVP,2012获得欧洲杯金靴奖、2013年获得联合会杯金靴奖。'

    pos = True
    seg_list = seg_to_list(text, pos)
    filter_list = word_filter(seg_list, pos)

    print('LSI模型结果:')
    topic_extract(filter_list, 'LSI', pos)
    print('LDA模型结果:')
    topic_extract(filter_list, 'LDA', pos)

执行结果如下:

LSI模型结果:
大赛/ 代表/ 个人/ 形式/ 职业/ 国际/ 日本/ 加盟/ 运动员/ 冠军/ 
LDA模型结果:
大赛/ 职业/ 运动员/ 冠军/ 日本/ 形式/ 个人/ 代表/ 国际/ 国家队/ 

参考:https://book.douban.com/subject/30247776/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

主题模型(Topic Model)与LDA算法 的相关文章

  • BERT - 池化输出与序列输出的第一个向量不同

    我在 Tensorflow 中使用 BERT 有一个细节我不太明白 根据文档 https tfhub dev google bert uncased L 12 H 768 A 12 1 https tfhub dev google bert
  • 将单引号替换为双引号并排除某些元素

    我想用双引号替换字符串中的所有单引号 但出现的情况除外 例如 n t ll m 等 input the stackoverflow don t said hey what output the stackoverflow don t sai
  • 否定句子的算法

    我想知道是否有人熟悉算法句子否定的任何尝试 例如 给定一个句子 这本书很好 请提供任意数量的意思相反的替代句子 例如 这本书不好 甚至 这本书不好 显然 以高精度实现这一点可能超出了当前 NLP 的范围 但我确信在这个主题上已经有了一些工作
  • 将 python NLTK 解析树保存到图像文件[重复]

    这个问题在这里已经有答案了 这可能会复制这个 stackoverflowquestion https stackoverflow com questions 23429117 saving nltk drawn parse tree to
  • BERT 输出不确定

    BERT 输出是不确定的 当我输入相同的输入时 我希望输出值是确定性的 但我的 bert 模型的值正在变化 听起来很尴尬 同一个值返回两次 一次 也就是说 一旦出现另一个值 就会出现相同的值并重复 如何使输出具有确定性 让我展示我的代码片段
  • 快速NLTK解析成语法树

    我正在尝试将数百个句子解析为语法树 我需要快速完成 问题是如果我使用 NLTK 那么我需要定义一个语法 而我不知道我只知道它会是英语 我尝试使用this https github com emilmont pyStatParser统计解析器
  • SpaCy 中的自定义句子边界检测

    我正在尝试在 spaCy 中编写一个自定义句子分段器 它将整个文档作为单个句子返回 我编写了一个自定义管道组件 它使用以下代码来执行此操作here https github com explosion spaCy issues 1850 但
  • 保存具有自定义前向功能的 Bert 模型并将其置于 Huggingface 上

    我创建了自己的 BertClassifier 模型 从预训练开始 然后添加由不同层组成的我自己的分类头 微调后 我想使用 model save pretrained 保存模型 但是当我打印它并从预训练上传时 我看不到我的分类器头 代码如下
  • 如何将标记化中的多单词名称保留在一起?

    我想使用 TF IDF 特征对文档进行分类 一种方法是 from sklearn feature extraction text import TfidfVectorizer import string import re import n
  • 斯坦福 CoreNLP:使用部分现有注释

    我们正在尝试利用现有的 代币化 句子分割 和命名实体标记 同时我们希望使用斯坦福 CoreNlp 额外为我们提供 词性标注 词形还原 和解析 目前 我们正在尝试以下方式 1 为 pos lemma parse 创建一个注释器 Propert
  • 验证 Transformer 中多头注意力的实现

    我已经实施了MultiAttention head in Transformers 周围有太多的实现 所以很混乱 有人可以验证我的实施是否正确 DotProductAttention 引用自 https www tensorflow org
  • 使用 OpenNLP 获取句子的解析树。陷入困境。

    OpenNLP 是一个关于自然语言处理的 Apache 项目 NLP 程序的目标之一是解析一个句子 并给出其语法结构的树 例如 天空是蓝色的 这句话 可能会被解析为 S NP VP The sky is blue where S是句子 NP
  • 使用 NLP 进行句子压缩 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 使用机器翻译 我可以获得一个句子的非常压缩的版本 例如 我真的很想喝一杯美味可口的咖啡将被翻译为我想喝咖
  • 分词统计方法

    我想解决分词问题 从没有空格的长字符串中解析单词 例如我们想要从中提取单词somelongword to some long word 我们可以通过字典的动态方法来实现这一点 但我们遇到的另一个问题是解析歧义 IE orcore gt or
  • 如何使用WordNet或与wordnet相关的类别来实现基于类别的文本标记?

    如何使用wordnet按单词类别标记文本 java作为接口 Example 考虑以下句子 1 计算机需要键盘 显示器 CPU才能工作 2 汽车使用齿轮和离合器 现在我的目标是 例句必须标记为 第 1 句话 电脑 电子键盘 电子中央处理器 电
  • Spacy提取特定名词短语

    我可以在 python 中使用 spacy 来查找具有特定邻居的 NP 吗 我想要文本中前后都有动词的名词短语 您可以合并名词短语 这样它们就不会单独标记化 分析依存解析树 查看相邻标记的 POS gt gt gt import spacy
  • BERT 获取句子嵌入

    我正在复制代码这一页 https colab research google com drive 1yFphU6PW9Uo6lmDly ud9a6c4RCYlwdX 我已将 BERT 模型下载到本地系统并获取句子嵌入 我有大约 500 00
  • 池化与随时间池化

    我从概念上理解最大 总和池中发生的情况作为 CNN 层操作 但我看到这个术语 随时间变化的最大池 或 随时间变化的总和池 例如 用于句子分类的卷积神经网络 https arxiv org pdf 1408 5882 pdfYoon Kim
  • 如何在 scikit-learn 的 SVM 中使用非整数字符串标签? Python

    Scikit learn 具有相当用户友好的用于机器学习的 python 模块 我正在尝试训练用于自然语言处理 NLP 的 SVM 标记器 其中我的标签和输入数据是单词和注释 例如 词性标记 而不是使用双精度 整数数据作为输入元组 1 2
  • 有人可以简单解释一下自然语言处理的要素吗?

    我是自然语言处理的新手 对所使用的术语感到困惑 什么是代币化 POS 标签 实体识别 标记化只是将文本分割成可以有意义的部分或为这些部分赋予含义 以及含义 当我确定某物是名词 动词或形容词时 它的名字是什么 如果我想分为日期 姓名 货币呢

随机推荐

  • 教你手机如何查看真实的IP地址

    有朋友不会查询自己手机的IP地址 很多时候我们需要使用vpn切换手机当前的IP 如何判断我们切换IP成功了呢 今天站长就教你手机如何查看目前真实的IP地址 1 打开手机浏览器 2 在搜索框里输入 ip 然后点击搜索 在搜索结果页面就会显示你
  • ESP32 上快捷部署 Tensorflow lite 机器学习(TinyML)

    在这篇文章中 我将向您展示使用 Arduino IDE 将 TensorFlow Lite 模型部署到 ESP32 的最简单方法 无需任何编译内容 Arduino 库 这个 Arduino 库是为了简化使用 Arduino IDE 将用于微
  • 4.8xml于json

    HTTP 协议 HyperText Transfer Protocol 超文本传输协议 是 TCP IP 协议集中的协议 是一个简单的请求 响应协议 指 定了客户端发送给服务器的消息以及服务器的响应 所有的 WWW 文件都必须遵守这个标准
  • matplotlib绘制饼状图

    源自http blog csdn net skyli114 article details 77508430 ticket ST 41707 PzNbUDGt6R5KYl3TkWDg passport csdn net pyplot使用pl
  • 接口测试基础

    目录 一 接口及接口测试概念 1 接口 接口的类型 2 接口测试 二 HTTP协议 1 HTTP协议的特点 2 URL格式 3 HTTP请求 4 HTTP响应 三 接口规范 1 传统风格接口 2 RESTful风格接口 四 接口测试流程 1
  • Python 11. OpenCV 透视变换

    import cv2 import numpy as np from matplotlib import pyplot as plt img cv2 imread pic4 PNG rows cols img shape 2 cv2 ims
  • 支持图文转换!PSD文档处理工具Aspose全新升级

    Aspose PSD是高级PSD和入门级AI文件格式操作API 允许创建和编辑Photoshop文件 并提供更新图层属性 添加水印 执行图形操作或将一种文件格式转换为另一种文件的功能 没有任何Adobe Photoshop或Adobe Il
  • [系统

    系统环境说明 系统 Deepin V20 平台 amd64 参考文献 asdf maven asdf document asdf plugins asdf vm安装 见多版本管理命令行工具asdf vm安装及使用 asdf vm安装Mave
  • 「C++学习笔记」面向.Net Core的(C++)CLR类库非专业入门(+使用Opencv)

    关键词 C CLR Net Core Net Famework Opencv C 目录 什么是CLR类库 本文说明 创建Demo程序 调用dll 通过项目引用 通过dll文件引用 其他还没完全清楚的坑 有关C CLI这块的资料真的很少而且都
  • 如何看待ChatGPT

    如何看待ChatGPT 如何看待ChatGPT 语言学家乔姆斯基说 这是一个抄袭的机器 欺骗性机器 ChatGPT使用大量文本数据进行训练 然后以一种令人信服的修饰语句展现 这使得它和人的互动能力更加契合 但是仍然不是一个充满创造力的智能机
  • 微信小程序之拨打电话

    微信小程序拨打电话功能的实现是采用wx makePhoneCall 具体方法如下 wxml lt view gt 电话 15888888888 lt view data ph 15888888888 bindtap callPhone gt
  • 【Android 12 AOSP学习】Android 12源码下载编译

    一 搭建环境 liunx系统 Ubuntu20 04 Android系统 12 1 安装 Repo 下载Repo前先安装 curl 库 sudo apt get install curl 下载好 curl 库后 设置清华源下载 Repo 然
  • 前端 JavaScript 提取 JSON 数据

    原文地址 假如我们从后端接收到了以下 JSON 数据 id 1 name Xu Albter age 18 使用 JSON parse 方法处理以上数据 将其转换为 JavaScript 对象 var obj JSON parse id 1
  • select函数缺陷分析

    与poll和epoll不同 select函数是事件为单位组织文件描述符 监视的行为较为单一 函数原型 int select int nfds fd set readfds fd set writefds fd set exceptfds s
  • 链表应用:两数相加

    关于链表 链表是一种极其重要的数据结构 因为对指针和抽象思维的要求较高 一度成为身边同学最痛恨的对象 我在将这里演示如何使用链表制作一个可以按位储存数字的容器 鉴于本人亦初学者 有错误请各位在评论区指正 这里还是以介绍链表为主 算法部分苦于
  • SpringCloud和微服务介绍

    SpringCloud介绍 微服务架构是什么 微服务实例的开发 服务的注册与发现 负载均衡 服务容错 API网关 分布式配置中心 调试 部署 持续集成 SpringCloud介绍 SpringCloud是在SpringBoot的基础上构建的
  • 一个完整详细的二维SVR案例分析过程

    文章目录 案例介绍 数据预处理 函数拟合仿真 SVR建模 模型调参 案例介绍 首先 此次案例是以油气开发为背景 选取加粗样式其中重要的两个参数含油饱和度和孔隙度分别作为此次案例的自变量和因变量进行试验 按照正常的案例分析步骤进行操作 此次为
  • 神经网络(ANN)

    算法介绍 概念 人工神经网络是由具有适应性的简单单元组成的广泛并行互连的网络 它的组织能够模拟生物神经神经系统对真实世界物体所作出的交互反应 在实际应用中 80 90 的人工神经网络模型是采用误差反转算法或其变形形式的网络模型 一个神经网络
  • 小程序的配置文件和小程序的模板语法

    微信小程序 小程序的配置文件 一个小程序应用程序会包括 会有最基本的两种配置文件 一种是全局的 app json 一种是页面自己的 page json 注意 配置文件中不可以出行注释 1 1 全局配置文件 app json app json
  • 主题模型(Topic Model)与LDA算法

    Topic Model 主题模型 Topic Model 是以非监督学习的方式对文档的隐含语义结构 latent semantic structure 进行聚类 clustering 的统计模型 主题模型认为在词 word 与文档 docu