Gensim - 快速指南
Gensim - 简介
本章将帮助您了解 Gensim 的历史和功能以及其用途和优势。
什么是 Gensim?
Gensim = "Generate Similar" 是一种流行的开源自然语言处理 (NLP) 库,用于无监督主题建模。它使用顶级学术模型和现代统计机器学习来执行各种复杂任务,例如−
- 构建文档或词向量
- 语料库
- 执行主题识别
- 执行文档比较(检索语义相似的文档)
- 分析纯文本文档的语义结构
除了执行上述复杂任务外,用 Python 和 Cython 实现的 Gensim 还旨在使用数据流和增量在线算法处理大型文本集合。这使得它不同于那些仅针对内存处理的机器学习软件包。
历史
2008 年,Gensim 最初是捷克数字数学的各种 Python 脚本的集合。在那里,它用于生成与特定文章最相似的文章的简短列表。但在 2009 年,RARE Technologies Ltd. 发布了其初始版本。然后,在 2019 年 7 月下旬,我们获得了其稳定版本 (3.8.0)。
各种功能
以下是 Gensim 提供的一些功能和能力 −
可扩展性
Gensim 可以使用其增量在线训练算法轻松处理大型和网络规模的语料库。它本质上是可扩展的,因为整个输入语料库不需要在任何时候完全驻留在随机存取存储器 (RAM) 中。换句话说,它的所有算法在语料库大小方面都是内存独立的。
健壮
Gensim 本质上是健壮的,并且已被各种人和组织在各种系统中使用了 4 年多。我们可以轻松插入我们自己的输入语料库或数据流。它也非常容易与其他向量空间算法一起扩展。
平台无关
众所周知,Python 是一种非常通用的语言,因为作为纯 Python,Gensim 可以在所有支持 Python 和 Numpy 的平台(如 Windows、Mac OS、Linux)上运行。
高效的多核实现
为了加快机器集群上的处理和检索速度,Gensim 提供了各种流行算法的高效多核实现,如潜在语义分析 (LSA)、潜在狄利克雷分配 (LDA)、随机投影 (RP)、分层狄利克雷过程 (HDP)。
开源和丰富的社区支持
Gensim 是根据 OSI 批准的 GNU LGPL 许可证授权的,允许它免费用于个人和商业用途。 Gensim 中的任何修改都是开源的,并且也拥有大量社区支持。
Gensim 的用途
Gensim 已在上千个商业和学术应用中使用和引用。它还被各种研究论文和学生论文引用。它包括以下流式并行实现 −
fastText
fastText 使用神经网络进行词嵌入,是一个用于学习词嵌入和文本分类的库。它由 Facebook 的 AI Research (FAIR) 实验室创建。该模型基本上允许我们创建监督或无监督算法来获取单词的向量表示。
Word2vec
用于生成词嵌入的 Word2vec 是一组浅层和两层神经网络模型。这些模型基本上经过训练以重建单词的语言上下文。
LSA(潜在语义分析)
它是 NLP(自然语言处理)中的一种技术,允许我们分析一组文档与其包含术语之间的关系。它是通过生成一组与文档和术语相关的概念来完成的。
LDA(潜在狄利克雷分配)
它是 NLP 中的一种技术,允许通过未观察到的组来解释观察集。这些未观察到的组解释了为什么某些数据部分相似。这就是它是一种生成统计模型的原因。
tf-idf(词频-逆文档频率)
tf-idf 是信息检索中的一种数字统计数据,反映了一个词对语料库中文档的重要性。搜索引擎经常使用它来根据用户查询对文档的相关性进行评分和排名。它还可用于文本摘要和分类中的停用词过滤。
所有这些都将在下一节中详细解释。
优点
Gensim 是一个进行主题建模的 NLP 包。Gensim 的重要优势如下 −
我们可能在其他包(如'scikit-learn'和'R')中获得主题建模和词嵌入的功能,但 Gensim 为构建主题模型和词嵌入所提供的功能是无与伦比的。它还为文本处理提供了更方便的功能。
Gensim 的另一个最显著的优势是,它让我们可以处理大型文本文件,甚至无需将整个文件加载到内存中。
Gensim 不需要昂贵的注释或手动标记文档,因为它使用无监督模型。
Gensim - 入门
本章介绍了安装 Gensim 的先决条件、其核心依赖项以及有关其当前版本的信息。
先决条件
为了安装 Gensim,我们必须在计算机上安装 Python。您可以转到链接 www.python.org/downloads/ 并选择适合您操作系统的最新版本,即 Windows 和 Linux/Unix。您可以参考链接 www.tutorialspoint.com/python3/index.htm 获取有关 Python 的基本教程。 Gensim 支持 Linux、Windows 和 Mac OS X。

代码依赖项
Gensim 应在任何支持 Python 2.7 或 3.5+ 和 NumPy 的平台上运行。它实际上依赖于以下软件 −
Python
Gensim 已使用 Python 版本 2.7、3.5、3.6 和 3.7 进行测试。
Numpy
众所周知,NumPy 是一个使用 Python 进行科学计算的软件包。它还可以用作通用数据的高效多维容器。Gensim 依赖 NumPy 软件包进行数字运算。有关 Python 的基本教程,您可以参考链接 www.tutorialspoint.com/numpy/index.htm。
smart_open
smart_open 是一个 Python 2 和 Python 3 库,用于高效地流式传输非常大的文件。它支持从/向存储(例如 S3、HDFS、WebHDFS、HTTP、HTTPS、SFTP 或本地文件系统)进行流式传输。 Gensim 依赖于 smart_open Python 库,用于透明地打开远程存储上的文件以及压缩文件。
当前版本
Gensim 的当前版本是 3.8.0,于 2019 年 7 月发布。
使用 终端
安装安装 Gensim 的最简单方法之一是在终端中运行以下命令 −
pip install --upgrade gensim
使用 Conda 环境安装
下载 Gensim 的另一种方法是使用 conda 环境。在您的 conda 终端中运行以下命令 −
conda install –c conda-forge gensim

使用 Source 包安装
假设您已下载并解压源包,则需要运行以下命令 −
python setup.py test python setup.py install
Gensim - 文档和语料库
在这里,我们将学习 Gensim 的核心概念,主要关注文档和语料库。
Gensim 的核心概念
以下是理解和使用 Gensim 所需的核心概念和术语 −
文档 − Z它指的是一些文本。
语料库 − 它指的是文档的集合。
向量 − 文档的数学表示称为向量。
模型 −它指的是一种用于将向量从一种表示形式转换为另一种表示形式的算法。
什么是文档?
如上所述,它指的是一些文本。如果我们详细了解,它是一个文本序列类型的对象,在 Python 3 中称为'str'。例如,在 Gensim 中,文档可以是任何内容,例如 −
- 140 个字符的短推文
- 单段,即文章或研究论文摘要
- 新闻文章
- 书籍
- 小说
- 论文
文本序列
文本序列类型在 Python 3 中通常称为'str'。众所周知,在 Python 中,文本数据是用字符串或更具体地说是'str'对象处理的。字符串基本上是 Unicode 代码点的不可变序列,可以用以下方式编写 −
单引号 − For example, 'Hi! How are you?'. It allows us to embed double quotes also. For example, 'Hi! "How" are you?'
双引号 − For example, "Hi! How are you?". It allows us to embed single quotes also. For example, "Hi! 'How' are you?"
三重引号 − It can have either three single quotes like, '''Hi! How are you?'''. or three double quotes like, """Hi! 'How' are you?"""
所有空格都将包含在字符串文字中。
示例
以下是 Gensim 中文档的示例 −
Document = "Tutorialspoint.com 是最大的在线教程库,而且全部免费"
什么是语料库?
语料库可以定义为在自然交流环境中生成的大型且结构化的机器可读文本集。在 Gensim 中,文档对象的集合称为语料库。语料库的复数形式为corpora。
语料库在 Gensim 中的作用
Gensim 中的语料库具有以下两个作用 −
用作训练模型的输入
语料库在 Gensim 中发挥的第一个也是最重要的作用是作为训练模型的输入。为了初始化模型的内部参数,在训练期间,模型会从训练语料库中寻找一些共同的主题和话题。如上所述,Gensim 专注于无监督模型,因此它不需要任何类型的人工干预。
用作主题提取器
一旦模型经过训练,它就可以用于从新文档中提取主题。这里,新文档是训练阶段未使用的文档。
示例
语料库可以包括某个人的所有推文、报纸上所有文章的列表或特定主题的所有研究论文等。
收集语料库
以下是包含 5 个文档的小型语料库的示例。这里,每个文档都是由单个句子组成的字符串。
t_corpus = [ "A survey of user opinion of computer system response time", "Relation of user perceived response time to error measurement", "The generation of random binary unordered trees", "The intersection graph of paths in trees", "Graph minors IV Widths of trees and well quasi ordering", ]
预处理收集语料库
一旦我们收集了语料库,就应该采取一些预处理步骤来保持语料库的简单性。我们可以简单地删除一些常用的英文单词,如"the"。我们也可以删除语料库中只出现一次的单词。
例如,以下 Python 脚本用于将每个文档小写,用空格将其拆分并过滤掉停用词 −
示例
import pprint t_corpus = [ "A survey of user opinion of computer system response time", "Relation of user perceived response time to error measurement", "The generation of random binary unordered trees", "The intersection graph of paths in trees", "Graph minors IV Widths of trees and well quasi ordering", ] stoplist = set('for a of the and to in'.split(' ')) processed_corpus = [[word for word in document.lower().split() if word not in stoplist] for document in t_corpus] pprint.pprint(processed_corpus) ]
输出
[['survey', 'user', 'opinion', 'computer', 'system', 'response', 'time'], ['relation', 'user', 'perceived', 'response', 'time', 'error', 'measurement'], ['generation', 'random', 'binary', 'unordered', 'trees'], ['intersection', 'graph', 'paths', 'trees'], ['graph', 'minors', 'iv', 'widths', 'trees', 'well', 'quasi', 'ordering']]
有效的预处理
Gensim 还提供了更有效的语料库预处理功能。在这种预处理中,我们可以将文档转换为小写标记列表。我们还可以忽略太短或太长的标记。这样的函数是gensim.utils.simple_preprocess(doc, deacc=False, min_len=2, max_len=15)。
gensim.utils.simple_preprocess() 函数
Gensim 提供此功能将文档转换为小写标记列表,并忽略太短或太长的标记。它具有以下参数 −
doc(str)
它指的是应对其应用预处理的输入文档。
deacc(bool, 可选)
此参数用于从标记中删除重音符号。它使用 deaccent() 来执行此操作。
min_len(int, 可选)
借助此参数,我们可以设置标记的最小长度。短于定义长度的标记将被丢弃。
max_len(int, 可选)
借助此参数,我们可以设置标记的最大长度。长于定义长度的标记将被丢弃。
此函数的输出将是从输入文档中提取的标记。
Gensim - 向量和模型
在这里,我们将学习 Gensim 的核心概念,主要关注向量和模型。
什么是向量?
如果我们想推断语料库中的潜在结构怎么办?为此,我们需要以一种可以数学操作的方式来表示文档。一种流行的表示方法是将语料库的每个文档表示为特征向量。这就是为什么我们可以说向量是文档的数学便捷表示。
举个例子,让我们将上面使用的语料库中的一个特征表示为 Q-A 对 −
Q − 单词 Hello 在文档中出现了多少次?
A −零 (0)。
Q − 文档中有多少个段落?
A − 二 (2)
问题通常用其整数 id 表示,因此该文档的表示是一系列对,如 (1, 0.0)、(2, 2.0)。这种向量表示被称为 密集 向量。为什么是 密集,因为它包含对上述所有问题的明确答案。
如果我们事先知道所有问题,表示可以很简单,如 (0, 2)。这样的答案序列(当然,如果事先知道问题)就是我们文档的 向量。
另一种流行的表示是 词袋 (BoW) 模型。在这种方法中,每个文档基本上都由一个向量表示,该向量包含字典中每个单词的频率计数。
举个例子,假设我们有一本字典,其中包含单词 ['Hello', 'How', 'are', 'you']。那么由字符串"How are you how"组成的文档将由向量 [0, 2, 1, 1] 表示。这里,向量的条目按"Hello"、"How"、"are"和"you"出现的顺序排列。
向量与文档
从上面对向量的解释中,文档和向量之间的区别几乎可以理解。但是,为了更清楚起见,文档是文本,而向量是该文本的数学上方便的表示。不幸的是,有时许多人会互换使用这些术语。
例如,假设我们有一个任意的文档 A,那么他们不会说"与文档 A 对应的向量",而是说"向量 A"或"文档 A"。这会导致很大的歧义。这里要注意的还有一件重要的事情是,两个不同的文档可能具有相同的向量表示。
将语料库转换为向量列表
在介绍将语料库转换为向量列表的实现示例之前,我们需要将语料库中的每个单词与一个唯一的整数 ID 相关联。为此,我们将扩展上一章中的示例。
示例
from gensim import corpora dictionary = corpora.Dictionary(processed_corpus) print(dictionary)
输出
Dictionary(25 unique tokens: ['computer', 'opinion', 'response', 'survey', 'system']...)
它表明在我们的语料库中,这个gensim.corpora.Dictionary中有 25 个不同的标记。
实施示例
我们可以使用字典将标记化的文档转换为这些 5 维向量,如下所示 −
pprint.pprint(dictionary.token2id)
输出
{ 'binary': 11, 'computer': 0, 'error': 7, 'generation': 12, 'graph': 16, 'intersection': 17, 'iv': 19, 'measurement': 8, 'minors': 20, 'opinion': 1, 'ordering': 21, 'paths': 18, 'perceived': 9, 'quasi': 22, 'random': 13, 'relation': 10, 'response': 2, 'survey': 3, 'system': 4, 'time': 5, 'trees': 14, 'unordered': 15, 'user': 6, 'well': 23, 'widths': 24 }
类似地,我们可以为文档创建词袋表示,如下所示 −
BoW_corpus = [dictionary.doc2bow(text) for text in processed_corpus] pprint.pprint(BoW_corpus)
输出
[ [(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1)], [(2, 1), (5, 1), (6, 1), (7, 1), (8, 1), (9, 1), (10, 1)], [(11, 1), (12, 1), (13, 1), (14, 1), (15, 1)], [(14, 1), (16, 1), (17, 1), (18, 1)], [(14, 1), (16, 1), (19, 1), (20, 1), (21, 1), (22, 1), (23, 1), (24, 1)] ]
什么是模型?
一旦我们将语料库矢量化,下一步做什么?现在,我们可以使用模型对其进行转换。模型可以称为用于将一种文档表示转换为另一种文档表示的算法。
正如我们所讨论的,在 Gensim 中,文档表示为向量,因此,我们可以将模型视为两个向量空间之间的转换。总是有一个训练阶段,模型会学习此类转换的细节。模型在训练阶段读取训练语料库。
初始化模型
让我们初始化 tf-idf 模型。该模型将向量从 BoW(词袋)表示转换为另一个向量空间,其中频率计数根据语料库中每个单词的相对稀有性进行加权。
实施示例
在下面的例子中,我们将初始化 tf-idf 模型。我们将在语料库上对其进行训练,然后转换字符串"trees graph"。
示例
from gensim import models tfidf = models.TfidfModel(BoW_corpus) words = "trees graph".lower().split() print(tfidf[dictionary.doc2bow(words)])
输出
[(3, 0.4869354917707381), (4, 0.8734379353188121)]
现在,一旦我们创建了模型,我们就可以通过 tfidf 转换整个语料库并对其进行索引,并查询我们的查询文档的相似性(我们给出查询文档'trees system')针对语料库中的每个文档 −
示例
from gensim import similarities index = similarities.SparseMatrixSimilarity(tfidf[BoW_corpus],num_features=5) query_document = 'trees system'.split() query_bow = dictionary.doc2bow(query_document) simils = index[tfidf[query_bow]] print(list(enumerate(simils)))
输出
[(0, 0.0), (1, 0.0), (2, 1.0), (3, 0.4869355), (4, 0.4869355)]
从上面的输出来看,文档 4 和文档 5 的相似度得分约为 49%。
此外,我们还可以按如下方式对该输出进行排序以提高可读性 −
示例
for doc_number, score in sorted(enumerate(sims), key=lambda x: x[1], reverse=True): print(doc_number, score)
输出
2 1.0 3 0.4869355 4 0.4869355 0 0.0 1 0.0
Gensim - 创建字典
在上一章中,我们讨论了向量和模型,您对字典有了一定了解。在这里,我们将更详细地讨论 Dictionary 对象。
什么是字典?
在深入研究字典的概念之前,让我们先了解一些简单的 NLP 概念 −
Token − 一个 token 表示一个"单词"。
Document − 一个 document 指的是一个句子或段落。
Corpus −它将文档集合称为词袋 (BoW)。
对于所有文档,语料库始终包含每个单词的标记 ID 及其在文档中的频率计数。
让我们转到 Gensim 中的字典概念。对于文本文档,Gensim 还需要将单词(即标记)转换为其唯一 ID。为了实现这一点,它为我们提供了 Dictionary 对象 的功能,该对象将每个单词映射到其唯一的整数 ID。它通过将输入文本转换为单词列表,然后将其传递给 corpora.Dictionary() 对象来实现此目的。
需要字典
现在出现的问题是,字典对象的实际需求是什么,以及它可以在哪里使用?在 Gensim 中,字典对象用于创建词袋 (BoW) 语料库,该语料库进一步用作主题建模和其他模型的输入。
文本输入的形式
我们可以为 Gensim 提供三种不同形式的输入文本 −
作为存储在 Python 原生列表对象中的句子(在 Python 3 中称为 str)
作为一个单一的文本文件(可以是小的或大的)
多个文本文件
使用 Gensim 创建字典
如上所述,在 Gensim 中,字典包含所有单词(又称标记)到其唯一整数 ID 的映射。我们可以从句子列表、一个或多个文本文件(包含多行文本的文本文件)创建字典。因此,首先让我们从使用句子列表创建字典开始。
从句子列表
在下面的例子中,我们将从句子列表创建字典。当我们有句子列表或您可以说多个句子时,我们必须将每个句子转换为单词列表,而理解是执行此操作的最常见方法之一。
实施示例
首先,按如下方式导入所需和必要的包 −
import gensim from gensim import corpora from pprint import pprint
接下来,从句子列表/文档中创建理解列表,以使用它创建字典 −
doc = [ "CNTK formerly known as Computational Network Toolkit", "is a free easy-to-use open-source commercial-grade toolkit", "that enable us to train deep learning algorithms to learn like the human brain." ]
接下来,我们需要将句子拆分成单词。这被称为标记化。
text_tokens = [[text for text in doc.split()] for doc in doc]
现在,借助以下脚本,我们可以创建字典 −
dict_LoS = corpora.Dictionary(text_tokens)
现在让我们获取更多信息,例如字典中的标记数量 −
print(dict_LoS)
输出
字典(27 个唯一标记:['CNTK', 'Computational', 'Network', 'Toolkit', 'as']...)
我们还可以看到单词唯一整数映射如下 −
print(dict_LoS.token2id)
输出
{ 'CNTK': 0, 'Computational': 1, 'Network': 2, 'Toolkit': 3, 'as': 4, 'formerly': 5, 'known': 6, 'a': 7, 'commercial-grade': 8, 'easy-to-use': 9, 'free': 10, 'is': 11, 'open-source': 12, 'toolkit': 13, 'algorithms': 14, 'brain.': 15, 'deep': 16, 'enable': 17, 'human': 18, 'learn': 19, 'learning': 20, 'like': 21, 'that': 22, 'the': 23, 'to': 24, 'train': 25, 'us': 26 }
完整实现示例
import gensim from gensim import corpora from pprint import pprint doc = [ "CNTK formerly known as Computational Network Toolkit", "is a free easy-to-use open-source commercial-grade toolkit", "that enable us to train deep learning algorithms to learn like the human brain." ] text_tokens = [[text for text in doc.split()] for doc in doc] dict_LoS = corpora.Dictionary(text_tokens) print(dict_LoS.token2id)
从单个文本文件
在下面的例子中,我们将从单个文本文件创建字典。以类似的方式,我们也可以从多个文本文件(即文件目录)创建字典。
为此,我们将上例中使用的文档保存在名为 doc.txt 的文本文件中。Gensim 将逐行读取文件并使用 simple_preprocess 一次处理一行。这样就不需要一次性将整个文件加载到内存中了。
实现示例
首先,导入所需的和必要的包,如下所示 −
import gensim from gensim import corpora from pprint import pprint from gensim.utils import simple_preprocess from smart_open import smart_open import os
下一行代码将使用名为 doc.txt 的单个文本文件创建 gensim 字典 −
dict_STF = corpora.Dictionary( simple_preprocess(line, deacc =True) for line in open('doc.txt', encoding='utf-8') )
现在让我们获取更多信息,例如字典中的标记数量 −
print(dict_STF)
输出
Dictionary(27 unique tokens: ['CNTK', 'Computational', 'Network', 'Toolkit', 'as']...)
我们还可以看到单词到唯一整数的映射,如下所示 −
print(dict_STF.token2id)
输出
{ 'CNTK': 0, 'Computational': 1, 'Network': 2, 'Toolkit': 3, 'as': 4, 'formerly': 5, 'known': 6, 'a': 7, 'commercial-grade': 8, 'easy-to-use': 9, 'free': 10, 'is': 11, 'open-source': 12, 'toolkit': 13, 'algorithms': 14, 'brain.': 15, 'deep': 16, 'enable': 17, 'human': 18, 'learn': 19, 'learning': 20, 'like': 21, 'that': 22, 'the': 23, 'to': 24, 'train': 25, 'us': 26 }
完整实现示例
import gensim from gensim import corpora from pprint import pprint from gensim.utils import simple_preprocess from smart_open import smart_open import os dict_STF = corpora.Dictionary( simple_preprocess(line, deacc =True) for line in open('doc.txt', encoding='utf-8') ) dict_STF = corpora.Dictionary(text_tokens) print(dict_STF.token2id)
来自多个文本文件
现在让我们从多个文件(即保存在同一目录中的多个文本文件)创建字典。对于此示例,我们创建了三个不同的文本文件,即 first.txt、second.txt 和 third.txt,其中包含我们在上一个示例中使用的文本文件 (doc.txt) 中的三行。所有这三个文本文件都保存在名为 ABC 的目录中。
实施示例
为了实现这一点,我们需要定义一个类,其中包含一个方法,该方法可以遍历目录 (ABC) 中的所有三个文本文件 (First、Second 和 Third.txt) 并生成处理后的单词标记列表。
让我们定义名为 Read_files 的类,该类具有一个名为 __iteration__() 的方法,如下所示 −
class Read_files(object): def __init__(self, directoryname): elf.directoryname = directoryname def __iter__(self): for fname in os.listdir(self.directoryname): for line in open(os.path.join(self.directoryname, fname), encoding='latin'): yield simple_preprocess(line)
接下来,我们需要提供目录的路径,如下所示 −
path = "ABC"
#提供您保存目录的计算机系统的路径。
接下来的步骤与前面的示例类似。下一行代码将使用包含三个文本文件的目录创建 Gensim 目录 −
dict_MUL = corpora.Dictionary(Read_files(path))
输出
Dictionary(27 个唯一标记:['CNTK', 'Computational', 'Network', 'Toolkit', 'as']...)
现在我们还可以看到单词到唯一整数的映射,如下所示 −
print(dict_MUL.token2id)
输出
{ 'CNTK': 0, 'Computational': 1, 'Network': 2, 'Toolkit': 3, 'as': 4, 'formerly': 5, 'known': 6, 'a': 7, 'commercial-grade': 8, 'easy-to-use': 9, 'free': 10, 'is': 11, 'open-source': 12, 'toolkit': 13, 'algorithms': 14, 'brain.': 15, 'deep': 16, 'enable': 17, 'human': 18, 'learn': 19, 'learning': 20, 'like': 21, 'that': 22, 'the': 23, 'to': 24, 'train': 25, 'us': 26 }
保存和加载 Gensim 字典
Gensim 支持其原生的 save() 方法将字典保存到磁盘,以及 load() 方法从磁盘加载字典。
例如,我们可以借助以下脚本保存字典 −
Gensim.corpora.dictionary.save(filename)
#提供您想要保存字典的路径。
同样,我们可以使用 load() 方法加载已保存的字典。以下脚本可以做到这一点 −
Gensim.corpora.dictionary.load(filename)
#提供您保存字典的路径。
Gensim - 创建词袋 (BoW) 语料库
我们已经了解了如何从文档列表和文本文件(从一个或多个文件)创建词典。现在,在本节中,我们将创建一个词袋 (BoW) 语料库。为了使用 Gensim,它是我们需要熟悉的最重要的对象之一。基本上,它是包含单词 ID 及其在每个文档中的频率的语料库。
创建 BoW 语料库
如前所述,在 Gensim 中,语料库包含单词 ID 及其在每个文档中的频率。我们可以从一个简单的文档列表和文本文件创建 BoW 语料库。我们需要做的是将标记化的单词列表传递给名为 Dictionary.doc2bow() 的对象。首先,让我们使用一个简单的文档列表创建 BoW 语料库。
从一个简单的句子列表
在下面的例子中,我们将从包含三个句子的简单列表创建 BoW 语料库。
首先,我们需要导入所有必要的包,如下所示 −
import gensim import pprint from gensim import corpora from gensim.utils import simple_preprocess
现在提供包含句子的列表。我们的列表中有三个句子 −
doc_list = [ "Hello, how are you?", "How do you do?", "Hey what are you doing? yes you What are you doing?" ]
接下来,对句子进行标记化,如下所示 −
doc_tokenized = [simple_preprocess(doc) for doc in doc_list]
创建一个 corpora.Dictionary() 对象,如下所示 −
dictionary = corpora.Dictionary()
现在将这些标记化的句子传递给 dictionary.doc2bow() 对象,如下所示 −
BoW_corpus = [dictionary.doc2bow(doc, allow_update=True) for doc in doc_tokenized]
最后我们可以打印词袋语料库 −
print(BoW_corpus)
输出
[ [(0, 1), (1, 1), (2, 1), (3, 1)], [(2, 1), (3, 1), (4, 2)], [(0, 2), (3, 3), (5, 2), (6, 1), (7, 2), (8, 1)] ]
上面的输出显示 id=0 的单词在第一个文档中出现一次(因为我们在输出中得到了 (0,1)),依此类推。
上面的输出不知何故无法被人类阅读。我们也可以将这些 id 转换为单词,但为此我们需要我们的字典进行转换,如下所示 −
id_words = [[(dictionary[id], count) for id, count in line] for line in BoW_corpus] print(id_words)
输出
[ [('are', 1), ('hello', 1), ('how', 1), ('you', 1)], [('how', 1), ('you', 1), ('do', 2)], [('are', 2), ('you', 3), ('doing', 2), ('hey', 1), ('what', 2), ('yes', 1)] ]
Now the above output is somehow human readable.
完整实现示例
import gensim import pprint from gensim import corpora from gensim.utils import simple_preprocess doc_list = [ "Hello, how are you?", "How do you do?", "Hey what are you doing? yes you What are you doing?" ] doc_tokenized = [simple_preprocess(doc) for doc in doc_list] dictionary = corpora.Dictionary() BoW_corpus = [dictionary.doc2bow(doc, allow_update=True) for doc in doc_tokenized] print(BoW_corpus) id_words = [[(dictionary[id], count) for id, count in line] for line in BoW_corpus] print(id_words)
来自文本文件
在下面的示例中,我们将从文本文件创建 BoW 语料库。为此,我们将上例中使用的文档保存在名为 doc.txt. 的文本文件中。
Gensim 将逐行读取文件并使用 simple_preprocess 一次处理一行。这样就不需要一次性将整个文件加载到内存中了。
实现示例
首先,导入所需的和必要的包,如下所示 −
import gensim from gensim import corpora from pprint import pprint from gensim.utils import simple_preprocess from smart_open import smart_open import os
接下来,下面这行代码将从doc.txt中读取文档并将其标记化 −
doc_tokenized = [ simple_preprocess(line, deacc =True) for line in open('doc.txt', encoding='utf-8') ] dictionary = corpora.Dictionary()
现在我们需要将这些标记化的单词传递到 dictionary.doc2bow() 对象中(如上例所示)
BoW_corpus = [ dictionary.doc2bow(doc, allow_update=True) for doc in doc_tokenized ] print(BoW_corpus)
输出
[ [(9, 1), (10, 1), (11, 1), (12, 1), (13, 1), (14, 1), (15, 1)], [ (15, 1), (16, 1), (17, 1), (18, 1), (19, 1), (20, 1), (21, 1), (22, 1), (23, 1), (24, 1) ], [ (23, 2), (25, 1), (26, 1), (27, 1), (28, 1), (29, 1), (30, 1), (31, 1), (32, 1), (33, 1), (34, 1), (35, 1), (36, 1) ], [(3, 1), (18, 1), (37, 1), (38, 1), (39, 1), (40, 1), (41, 1), (42, 1), (43, 1)], [ (18, 1), (27, 1), (31, 2), (32, 1), (38, 1), (41, 1), (43, 1), (44, 1), (45, 1), (46, 1), (47, 1), (48, 1), (49, 1), (50, 1), (51, 1), (52, 1) ] ]
doc.txt 文件包含以下内容 −
CNTK 以前称为计算网络工具包,是一个免费的易于使用的开源商业级工具包,使我们能够训练深度学习算法,使其像人脑一样学习。
您可以在 tutorialspoint.com 上找到它的免费教程,还免费提供有关 AI 深度学习机器学习等技术的最佳技术教程。
完整实现示例
import gensim from gensim import corpora from pprint import pprint from gensim.utils import simple_preprocess from smart_open import smart_open import os doc_tokenized = [ simple_preprocess(line, deacc =True) for line in open('doc.txt', encoding='utf-8') ] dictionary = corpora.Dictionary() BoW_corpus = [dictionary.doc2bow(doc, allow_update=True) for doc in doc_tokenized] print(BoW_corpus)
保存和加载 Gensim 语料库
我们可以借助以下脚本保存语料库 −
corpora.MmCorpus.serialize('/Users/Desktop/BoW_corpus.mm', bow_corpus)
#提供语料库的路径和名称。语料库的名称是 BoW_corpus,我们将其保存为 Matrix Market 格式。
同样,我们可以使用以下脚本加载已保存的语料库 −
corpus_load = corpora.MmCorpus('/Users/Desktop/BoW_corpus.mm') for line in corpus_load: print(line)
Gensim - 转换
本章将帮助您了解 Gensim 中的各种转换。让我们从了解转换文档开始。
转换文档
转换文档意味着以某种方式表示文档,以便可以对文档进行数学操作。除了推断语料库的潜在结构之外,转换文档还将实现以下目标 −
它发现了单词之间的关系。
它揭示了语料库中的隐藏结构。
它以一种新的、更具语义的方式描述文档。
它使文档的表示更加紧凑。
它提高了效率,因为新的表示消耗更少的资源。
它提高了功效,因为在新的表示中忽略了边际数据趋势。
在新的文档表示中,噪音也减少了。
让我们看看将文档从一个向量空间表示转换为另一个向量空间表示的实现步骤。
实施步骤
按顺序要转换文档,我们必须遵循以下步骤 −
步骤 1:创建语料库
第一个也是最基本的步骤是从文档创建语料库。我们已经在前面的例子中创建了语料库。让我们创建另一个具有一些增强功能的语料库(删除常用词和仅出现一次的词)−
import gensim import pprint from collections import defaultdict from gensim import corpora
现在提供用于创建语料库的文档−
t_corpus = ["CNTK formerly known as Computational Network Toolkit", "is a free easy-to-use open-source commercial-grade toolkit", "that enable us to train deep learning algorithm to learn like the human brain.", "You can find its free tutorial on tutorialspoint.com", "Tutorialspoint.com also provide best technology tutorials on technologies like AI deep learning machine learning for free"]
接下来,我们需要进行 tokenise,同时删除常用词 −
stoplist = set('for a of the and to in'.split(' ')) processed_corpus = [ [ word for word in document.lower().split() if word not in stoplist ] for document in t_corpus ]
以下脚本将删除仅出现在 −
frequency = defaultdict(int) for text in processed_corpus: for token in text: frequency[token] += 1 processed_corpus = [ [token for token in text if frequency[token] > 1] for text in processed_corpus ] pprint.pprint(processed_corpus)
输出
[ ['toolkit'], ['free', 'toolkit'], ['deep', 'learning', 'like'], ['free', 'on', 'tutorialspoint.com'], ['tutorialspoint.com', 'on', 'like', 'deep', 'learning', 'learning', 'free'] ]
现在将其传递给 corpora.dictionary() 对象以获取我们语料库中的唯一对象 −
dictionary = corpora.Dictionary(processed_corpus) print(dictionary)
输出
Dictionary(7 unique tokens: ['toolkit', 'free', 'deep', 'learning', 'like']...)
接下来,以下代码行将为我们的语料库创建 Bag of Word 模型 −
BoW_corpus = [dictionary.doc2bow(text) for text in processed_corpus] pprint.pprint(BoW_corpus)
输出
[ [(0, 1)], [(0, 1), (1, 1)], [(2, 1), (3, 1), (4, 1)], [(1, 1), (5, 1), (6, 1)], [(1, 1), (2, 1), (3, 2), (4, 1), (5, 1), (6, 1)] ]
步骤 2:创建转换
转换是一些标准的 Python 对象。我们可以使用经过训练的语料库初始化这些转换,即 Python 对象。在这里,我们将使用 tf-idf 模型来创建经过训练的语料库的转换,即 BoW_corpus。
首先,我们需要从 gensim 导入模型包。
from gensim import models
现在,我们需要按如下方式初始化模型 −
tfidf = models.TfidfModel(BoW_corpus)
步骤 3:转换向量
现在,在这最后一步中,向量将从旧表示转换为新表示。由于我们已在上述步骤中初始化了 tfidf 模型,因此 tfidf 现在将被视为只读对象。在这里,通过使用这个 tfidf 对象,我们将向量从词袋表示(旧表示)转换为 Tfidf 实值权重(新表示)。
doc_BoW = [(1,1),(3,1)] print(tfidf[doc_BoW]
输出
[(1, 0.4869354917707381), (3, 0.8734379353188121)]
我们对语料库的两个值应用了转换,但我们也可以将其应用于整个语料库,如下所示 −
corpus_tfidf = tfidf[BoW_corpus] for doc in corpus_tfidf: print(doc)
输出
[(0, 1.0)] [(0, 0.8734379353188121), (1, 0.4869354917707381)] [(2, 0.5773502691896257), (3, 0.5773502691896257), (4, 0.5773502691896257)] [(1, 0.3667400603126873), (5, 0.657838022678017), (6, 0.657838022678017)] [ (1, 0.19338287240886842), (2, 0.34687949360312714), (3, 0.6937589872062543), (4, 0.34687949360312714), (5, 0.34687949360312714), (6, 0.34687949360312714) ]
完整实现示例
import gensim import pprint from collections import defaultdict from gensim import corpora t_corpus = [ "CNTK formerly known as Computational Network Toolkit", "is a free easy-to-use open-source commercial-grade toolkit", "that enable us to train deep learning algorithms to learn like the human brain.", "You can find its free tutorial on tutorialspoint.com", "Tutorialspoint.com also provide best technical tutorials on technologies like AI deep learning machine learning for free" ] stoplist = set('for a of the and to in'.split(' ')) processed_corpus = [ [word for word in document.lower().split() if word not in stoplist] for document in t_corpus ] frequency = defaultdict(int) for text in processed_corpus: for token in text: frequency[token] += 1 processed_corpus = [ [token for token in text if frequency[token] > 1] for text in processed_corpus ] pprint.pprint(processed_corpus) dictionary = corpora.Dictionary(processed_corpus) print(dictionary) BoW_corpus = [dictionary.doc2bow(text) for text in processed_corpus] pprint.pprint(BoW_corpus) from gensim import models tfidf = models.TfidfModel(BoW_corpus) doc_BoW = [(1,1),(3,1)] print(tfidf[doc_BoW]) corpus_tfidf = tfidf[BoW_corpus] for doc in corpus_tfidf: print(doc)
Gensim 中的各种转换
使用 Gensim,我们可以实现各种流行的转换,即向量空间模型算法。其中一些如下 −
Tf-Idf(词频-逆文档频率)
在初始化期间,此 tf-idf 模型算法期望训练语料库具有整数值(例如 Bag-of-Words 模型)。然后,在转换时,它采用向量表示并返回另一个向量表示。
输出向量将具有相同的维数,但稀有特征的值(在训练时)将增加。它基本上将整数值向量转换为实值向量。以下是 Tf-idf 转换的语法 −
Model=models.TfidfModel(corpus, normalize=True)
LSI(潜在语义索引)
LSI 模型算法可以将文档从整数值向量模型(例如 Bag-of-Words 模型)或 Tf-Idf 加权空间转换为潜在空间。输出向量将具有较低的维度。以下是 LSI 转换的语法 −
Model=models.LsiModel(tfidf_corpus, id2word=dictionary, num_topics=300)
LDA(潜在狄利克雷分配)
LDA 模型算法是另一种将文档从词袋模型空间转换为主题空间的算法。输出向量将具有较低的维度。以下是 LSI 转换的语法 −
Model=models.LdaModel(corpus, id2word=dictionary, num_topics=100)
随机投影 (RP)
RP 是一种非常有效的方法,旨在降低向量空间的维数。这种方法基本上是近似文档之间的 Tf-Idf 距离。它通过加入一些随机性来实现这一点。
Model=models.RpModel(tfidf_corpus, num_topics=500)
分层狄利克雷过程 (HDP)
HDP 是一种非参数贝叶斯方法,是 Gensim 的新增功能。我们在使用它时应该小心谨慎。
Model=models.HdpModel(corpus, id2word=dictionary
Gensim - 创建 TF-IDF 矩阵
在这里,我们将学习如何在 Gensim 的帮助下创建词频-逆文档频率 (TF-IDF) 矩阵。
什么是 TF-IDF?
它是词频-逆文档频率模型,也是一个词袋模型。它与常规语料库不同,因为它降低了标记的权重,即在文档中频繁出现的单词。在初始化期间,此 tf-idf 模型算法期望训练语料库具有整数值(例如词袋模型)。
然后在转换时,它采用向量表示并返回另一个向量表示。输出向量将具有相同的维数,但稀有特征的值(在训练时)将增加。它基本上将整数值向量转换为实值向量。
如何计算?
TF-IDF 模型通过以下两个简单步骤计算 tfidf −
步骤 1:将局部和全局分量相乘
在此第一步中,模型将局部分量(例如 TF(词频))与全局分量(例如 IDF(逆文档频率))相乘。
步骤 2:将结果标准化
完成乘法后,下一步 TFIDF 模型将结果标准化为单位长度。
由于上述两个步骤,文档中经常出现的单词将被降低权重。
如何获得 TF-IDF 权重?
在这里,我们将实现一个示例来查看如何获得 TF-IDF 权重。基本上,为了获得 TF-IDF 权重,我们首先需要训练语料库,然后在 tfidf 模型中应用该语料库。
训练语料库
如上所述,要获得 TF-IDF,我们首先需要训练我们的语料库。首先,我们需要导入所有必要的包,如下所示 −
import gensim import pprint from gensim import corpora from gensim.utils import simple_preprocess
现在提供包含句子的列表。我们的列表中有三个句子 −
doc_list = [ "Hello, how are you?", "How do you do?", "Hey what are you doing? yes you What are you doing?" ]
接下来,对句子进行标记化,如下所示 −
doc_tokenized = [simple_preprocess(doc) for doc in doc_list]
创建 corpora.Dictionary() 的对象,如下所示 −
dictionary = corpora.Dictionary()
现在将这些标记化的句子传递给 dictionary.doc2bow() 对象,如下所示 −
BoW_corpus = [dictionary.doc2bow(doc, allow_update=True) for doc in doc_tokenized]
接下来,我们将获取文档中的单词 ID 及其频率。
for doc in BoW_corpus: print([[dictionary[id], freq] for id, freq in doc])
输出
[['are', 1], ['hello', 1], ['how', 1], ['you', 1]] [['how', 1], ['you', 1], ['do', 2]] [['are', 2], ['you', 3], ['doing', 2], ['hey', 1], ['what', 2], ['yes', 1]]
这样我们就训练好了我们的语料库(Bag-of-Word 语料库)。
接下来,我们需要将这个训练好的语料库应用到 tfidf 模型 models.TfidfModel() 中。
首先导入 numpay 包 −
import numpy as np
现在将我们训练好的语料库(BoW_corpus)应用到 models.TfidfModel()
的方括号中tfidf = models.TfidfModel(BoW_corpus, smartirs='ntc')
接下来,我们将在我们的 tfidf 模型语料库中获得单词 id 及其频率 −
for doc in tfidf[BoW_corpus]: print([[dictionary[id], np.around(freq,decomal=2)] for id, freq in doc])
输出
[['are', 0.33], ['hello', 0.89], ['how', 0.33]] [['how', 0.18], ['do', 0.98]] [['are', 0.23], ['doing', 0.62], ['hey', 0.31], ['what', 0.62], ['yes', 0.31]] [['are', 1], ['hello', 1], ['how', 1], ['you', 1]] [['how', 1], ['you', 1], ['do', 2]] [['are', 2], ['you', 3], ['doing', 2], ['hey', 1], ['what', 2], ['yes', 1]] [['are', 0.33], ['hello', 0.89], ['how', 0.33]] [['how', 0.18], ['do', 0.98]] [['are', 0.23], ['doing', 0.62], ['hey', 0.31], ['what', 0.62], ['yes', 0.31]]
从上面的输出中,我们可以看到文档中单词频率的差异。
完整的实现示例
import gensim import pprint from gensim import corpora from gensim.utils import simple_preprocess doc_list = [ "Hello, how are you?", "How do you do?", "Hey what are you doing? yes you What are you doing?" ] doc_tokenized = [simple_preprocess(doc) for doc in doc_list] dictionary = corpora.Dictionary() BoW_corpus = [dictionary.doc2bow(doc, allow_update=True) for doc in doc_tokenized] for doc in BoW_corpus: print([[dictionary[id], freq] for id, freq in doc]) import numpy as np tfidf = models.TfidfModel(BoW_corpus, smartirs='ntc') for doc in tfidf[BoW_corpus]: print([[dictionary[id], np.around(freq,decomal=2)] for id, freq in doc])
单词权重的差异
如上所述,文档中出现频率越高的单词获得的权重就越小。让我们从上述两个输出中了解单词权重的差异。单词'are'出现在两个文档中,并且权重被降低了。类似地,单词'you'出现在所有文档中,并且被一起删除。
Gensim - 主题建模
本章讨论与 Gensim 相关的主题建模。
要注释我们的数据并理解句子结构,最好的方法之一是使用计算语言算法。毫无疑问,借助这些计算语言算法,我们可以了解有关数据的一些更详细的信息,但是,
我们能知道在我们的语料库中哪种词比其他词出现的频率更高吗?
我们可以对数据进行分组吗?
我们可以在数据中找到潜在主题吗?
借助主题建模,我们可以实现所有这些目标。那么让我们深入探讨主题模型的概念。
什么是主题模型?
主题模型可以定义为包含有关文本中主题信息的概率模型。但这里出现了两个重要问题,如下所示 −
首先,主题到底是什么?
顾名思义,主题是文本中所代表的基本思想或主题。举个例子,包含报纸文章的语料库将包含与金融、天气、政治、体育、各州新闻等相关的主题。
其次,主题模型在文本处理中的重要性是什么?
众所周知,为了识别文本中的相似性,我们可以使用单词进行信息检索和搜索技术。但是,借助主题模型,我们现在可以使用主题而不是单词来搜索和排列文本文件。
从这个意义上说,我们可以说主题是单词的概率分布。这就是为什么通过使用主题模型,我们可以将文档描述为主题的概率分布。
主题模型的目标
如上所述,主题建模的重点是基本思想和主题。其主要目标如下 −
主题模型可用于文本摘要。
它们可用于组织文档。例如,我们可以使用主题建模将新闻文章分组为有组织的/相互关联的部分,例如组织与板球相关的所有新闻文章。
它们可以改善搜索结果。如何?对于搜索查询,我们可以使用主题模型来显示包含不同关键字但内容相同的文档。
推荐的概念对于营销非常有用。它被各种在线购物网站、新闻网站等使用。主题模型有助于提出关于购买什么、下一步阅读什么等的建议。它们通过在列表中查找具有共同主题的材料来实现这一点。
Gensim 中的主题建模算法
毫无疑问,Gensim 是最流行的主题建模工具包。它的免费可用性和 Python 使其更受欢迎。在本节中,我们将讨论一些最流行的主题建模算法。在这里,我们将重点关注"是什么"而不是"如何",因为 Gensim 为我们很好地抽象了它们。
潜在狄利克雷分配 (LDA)
潜在狄利克雷分配 (LDA) 是目前用于主题建模的最常见和最流行的技术。它是 Facebook 研究人员在 2013 年发表的研究论文中使用的方法。它最初由 David Blei、Andrew Ng 和 Michael Jordan 于 2003 年提出。他们在论文中提出了 LDA,论文标题很简单,就是潜在狄利克雷分配。
LDA 的特点
让我们通过它的特点 − 来更多地了解这种奇妙的技术
概率主题建模技术
LDA 是一种概率主题建模技术。正如我们上面所讨论的,在主题建模中,我们假设在任何一组相互关联的文档(可能是学术论文、报纸文章、Facebook 帖子、推文、电子邮件等)中,每个文档都包含一些主题组合。
概率主题建模的主要目标是发现相互关联的文档集合的隐藏主题结构。主题结构通常包括以下三项内容 −
主题
文档中主题的统计分布
文档中构成主题的单词
以无监督的方式工作
LDA 以无监督的方式工作。这是因为,LDA 使用条件概率来发现隐藏的主题结构。它假设主题在整个相关文档集合中分布不均匀。
在 Gensim 中非常容易创建它
在 Gensim 中,创建 LDA 模型非常容易。我们只需要指定语料库、字典映射和我们想要在模型中使用的主题数量。
Model=models.LdaModel(corpus, id2word=dictionary, num_topics=100)
可能面临计算上难以解决的问题
计算每个可能的主题结构的概率是 LDA 面临的计算挑战。这很有挑战性,因为它需要计算每个观察到的单词在每个可能的主题结构下的概率。如果我们有大量的主题和单词,LDA 可能面临计算上难以解决的问题。
潜在语义索引 (LSI)
在 Gensim 中使用潜在狄利克雷分配 (LDA)首次实现的主题建模算法是潜在语义索引 (LSI)。它也被称为潜在语义分析 (LSA)。
它于 1988 年由 Scott Deerwester、Susan Dumais、George Furnas、Richard Harshman、Thomas Landaur、Karen Lochbaum 和 Lynn Streeter 获得专利。在本节中,我们将设置我们的 LSI 模型。它可以以与设置 LDA 模型相同的方式完成。我们需要从 gensim.models 导入 LSI 模型。
LSI 的作用
实际上,LSI 是一种 NLP 技术,尤其是在分布式语义方面。它分析一组文档与这些文档包含的术语之间的关系。如果我们谈论它的工作原理,那么它会从一大段文本中构建一个包含每个文档的字数的矩阵。
构建后,为了减少行数,LSI 模型使用一种称为奇异值分解 (SVD) 的数学技术。除了减少行数外,它还保留了列之间的相似性结构。在矩阵中,行代表唯一的单词,列代表每个文档。它基于分布假设工作,即假设含义相近的单词会出现在同一类文本中。
Model=models.LsiModel(corpus, id2word=dictionary, num_topics=100)
分层狄利克雷过程 (HDP)
LDA 和 LSI 等主题模型有助于总结和组织无法手动分析的大量文本档案。除了 LDA 和 LSI,Gensim 中另一个强大的主题模型是 HDP(分层狄利克雷过程)。它基本上是一个用于对分组数据进行无监督分析的混合成员模型。与 LDA(其有限对应物)不同,HDP 从数据中推断出主题数量。
Model=models.HdpModel(corpus, id2word=dictionary
Gensim - 创建 LDA 主题模型
本章将帮助您了解如何在 Gensim 中创建隐含狄利克雷分配 (LDA) 主题模型。
在 NLP(自然语言处理)的主要应用之一中,自动从大量文本中提取有关主题的信息。大量文本可能是来自酒店评论、推文、Facebook 帖子、任何其他社交媒体渠道的提要、电影评论、新闻报道、用户反馈、电子邮件等。
在这个数字时代,了解人们/客户在谈论什么,了解他们的观点和问题,对企业、政治运动和管理员来说非常有价值。但是,是否可以手动阅读如此大量的文本,然后从主题中提取信息?
不,不可能。它需要一种自动算法,可以读取这些大量的文本文档并自动从中提取所需的信息/讨论主题。
LDA 的作用
LDA 的主题建模方法是将文档中的文本分类到特定主题。 LDA 以狄利克雷分布建模,构建 −
- 每个文档一个主题模型和
- 每个主题一个词模型
在提供 LDA 主题模型算法后,为了获得良好的主题-关键词分布组合,它重新排列 −
- 文档内的主题分布和
- 主题内的关键词分布
在处理过程中,LDA 做出的一些假设是 −
- 每个文档都被建模为主题的多项式分布。
- 每个主题都被建模为词的多项式分布。
- 我们必须选择正确的数据语料库,因为 LDA 假设每个文本块都包含相关的单词。
- LDA 还假设文档是由多种主题组成的。
使用 Gensim 实现
在这里,我们将使用 LDA(潜在狄利克雷分配)从数据集中提取自然讨论的主题。
加载数据集
我们将要使用的数据集是 '20 个新闻组' 的数据集,其中包含来自新闻报道各个部分的数千篇新闻文章。它可在 Sklearn 数据集下找到。我们可以通过以下 Python 脚本轻松下载 −
from sklearn.datasets import fetch_20newsgroups newsgroups_train = fetch_20newsgroups(subset='train')
让我们通过以下脚本查看一些示例新闻 −
newsgroups_train.data[:4]
["From: lerxst@wam.umd.edu (where's my thing) Subject: WHAT car is this!? Nntp-Posting-Host: rac3.wam.umd.edu Organization: University of Maryland, College Park Lines: 15 I was wondering if anyone out there could enlighten me on this car I saw the other day. It was a 2-door sports car, looked to be from the late 60s/ early 70s. It was called a Bricklin. The doors were really small. In addition, the front bumper was separate from the rest of the body. This is all I know. If anyone can tellme a model name, engine specs, years of production, where this car is made, history, or whatever info you have on this funky looking car, please e-mail. Thanks, - IL ---- brought to you by your neighborhood Lerxst ---- ", "From: guykuo@carson.u.washington.edu (Guy Kuo) Subject: SI Clock Poll - Final Call Summary: Final call for SI clock reports Keywords: SI,acceleration,clock,upgrade Article-I.D.: shelley.1qvfo9INNc3s Organization: University of Washington Lines: 11 NNTP-Posting-Host: carson.u.washington.edu A fair number of brave souls who upgraded their SI clock oscillator have shared their experiences for this poll. Please send a brief message detailing your experiences with the procedure. Top speed attained, CPU rated speed, add on cards and adapters, heat sinks, hour of usage per day, floppy disk functionality with 800 and 1.4 m floppies are especially requested. I will be summarizing in the next two days, so please add to the network knowledge base if you have done the clock upgrade and haven't answered this poll. Thanks. Guy Kuo <;guykuo@u.washington.edu> ", 'From: twillis@ec.ecn.purdue.edu (Thomas E Willis) Subject: PB questions... Organization: Purdue University Engineering Computer Network Distribution: usa Lines: 36 well folks, my mac plus finally gave up the ghost this weekend after starting life as a 512k way back in 1985. sooo, i\'m in the market for a new machine a bit sooner than i intended to be... i\'m looking into picking up a powerbook 160 or maybe 180 and have a bunch of questions that (hopefully) somebody can answer: * does anybody know any dirt on when the next round of powerbook introductions are expected? i\'d heard the 185c was supposed to make an appearence "this summer" but haven\'t heard anymore on it - and since i don\'t have access to macleak, i was wondering if anybody out there had more info... * has anybody heard rumors about price drops to the powerbook line like the ones the duo\'s just went through recently? * what\'s the impression of the display on the 180? i could probably swing a 180 if i got the 80Mb disk rather than the 120, but i don\'t really have a feel for how much "better" the display is (yea, it looks great in the store, but is that all "wow" or is it really that good?). could i solicit some opinions of people who use the 160 and 180 day-to-day on if its worth taking the disk size and money hit to get the active display? (i realize this is a real subjective question, but i\'ve only played around with the machines in a computer store breifly and figured the opinions of somebody who actually uses the machine daily might prove helpful). * how well does hellcats perform? ;) thanks a bunch in advance for any info - if you could email, i\'ll post a summary (news reading time is at a premium with finals just around the corner... : ( ) -- Tom Willis \ twillis@ecn.purdue.edu \ Purdue Electrical Engineering ---------------------------------------------------------------------------\ n"Convictions are more dangerous enemies of truth than lies." - F. W. Nietzsche ', 'From: jgreen@amber (Joe Green) Subject: Re: Weitek P9000 ? Organization: Harris Computer Systems Division Lines: 14 Distribution: world NNTP-Posting-Host: amber.ssd.csd.harris.com X-Newsreader: TIN [version 1.1 PL9] Robert J.C. Kyanko (rob@rjck.UUCP) wrote: >abraxis@iastate.edu writes in article <abraxis.734340159@class1.iastate.edu >: > > Anyone know about the Weitek P9000 graphics chip? > As far as the low-level stuff goes, it looks pretty nice. It\'s got this > quadrilateral fill command that requires just the four points. Do you have Weitek\'s address/phone number? I\'d like to get some information about this chip. -- Joe Green Harris Corporation jgreen@csd.harris.com Computer Systems Division "The only thing that really scares me is a person with no sense of humor. " -- Jonathan Winters ']
先决条件
我们需要 NLTK 中的停用词和 Scapy 中的英语模型。两者都可以通过以下方式下载 −
import nltk; nltk.download('stopwords') nlp = spacy.load('en_core_web_md', disable=['parser', 'ner'])
导入必要的包
为了构建 LDA 模型,我们需要导入以下必要的包 −
import re import numpy as np import pandas as pd from pprint import pprint import gensim import gensim.corpora as corpora from gensim.utils import simple_preprocess from gensim.models import CoherenceModel import spacy import pyLDAvis import pyLDAvis.gensim import matplotlib.pyplot as plt
准备停用词
现在,我们需要导入停用词并使用它们 −
from nltk.corpus import stopwords stop_words = stopwords.words('english') stop_words.extend(['from', 'subject', 're', 'edu', 'use'])
清理文本
现在,借助 Gensim 的 simple_preprocess(),我们需要将每个句子标记为一个单词列表。我们还应该删除标点符号和不必要的字符。为了做到这一点,我们将创建一个名为 sent_to_words() 的函数 −
def sent_to_words(sentences): for sentence in sentences: yield(gensim.utils.simple_preprocess(str(sentence), deacc=True)) data_words = list(sent_to_words(data))
构建二元词组和三元词组模型
众所周知,二元词组是文档中经常一起出现的两个词,而三元词组是文档中经常一起出现的三个词。借助 Gensim 的 Phrases 模型,我们可以做到这一点 −
bigram = gensim.models.Phrases(data_words, min_count=5, Threshold=100) trigram = gensim.models.Phrases(bigram[data_words], Threshold=100) bigram_mod = gensim.models.phrases.Phraser(bigram) trigram_mod = gensim.models.phrases.Phraser(trigram)
过滤掉停用词
接下来,我们需要过滤掉停用词。除此之外,我们还将创建用于制作二元组、三元组和词形还原的函数 −
def remove_stopwords(texts): return [[word for word in simple_preprocess(str(doc)) if word not in stop_words] for doc in texts] def make_bigrams(texts): return [bigram_mod[doc] for doc in texts] def make_trigrams(texts): return [trigram_mod[bigram_mod[doc]] for doc in texts] def lemmatization(texts, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV']): texts_out = [] for sent in texts: doc = nlp(" ".join(sent)) texts_out.append([token.lemma_ for token in doc if token.pos_ in allowed_postags]) return texts_out
为主题模型构建词典和语料库
现在我们需要构建词典和语料库。我们在前面的例子中也做过 −
id2word = corpora.Dictionary(data_lemmatized) texts = data_lemmatized corpus = [id2word.doc2bow(text) for text in texts]
构建 LDA 主题模型
我们已经实现了训练 LDA 模型所需的一切。现在是时候构建 LDA 主题模型了。对于我们的实现示例,可以借助以下代码行来完成 −
lda_model = gensim.models.ldamodel.LdaModel( corpus=corpus, id2word=id2word, num_topics=20, random_state=100, update_every=1, chunksize=100, passes=10, alpha='auto', per_word_topics=True )
实现示例
让我们看看构建 LDA 主题模型的完整实现示例 −
import re import numpy as np import pandas as pd from pprint import pprint import gensim import gensim.corpora as corpora from gensim.utils import simple_preprocess from gensim.models import CoherenceModel import spacy import pyLDAvis import pyLDAvis.gensim import matplotlib.pyplot as plt from nltk.corpus import stopwords stop_words = stopwords.words('english') stop_words.extend(['from', 'subject', 're', 'edu', 'use']) from sklearn.datasets import fetch_20newsgroups newsgroups_train = fetch_20newsgroups(subset='train') data = newsgroups_train.data data = [re.sub('\S*@\S*\s?', '', sent) for sent in data] data = [re.sub('\s+', ' ', sent) for sent in data] data = [re.sub("\'", "", sent) for sent in data] print(data_words[:4]) #it will print the data after prepared for stopwords bigram = gensim.models.Phrases(data_words, min_count=5, threshold=100) trigram = gensim.models.Phrases(bigram[data_words], threshold=100) bigram_mod = gensim.models.phrases.Phraser(bigram) trigram_mod = gensim.models.phrases.Phraser(trigram) def remove_stopwords(texts): return [[word for word in simple_preprocess(str(doc)) if word not in stop_words] for doc in texts] def make_bigrams(texts): return [bigram_mod[doc] for doc in texts] def make_trigrams(texts): [trigram_mod[bigram_mod[doc]] for doc in texts] def lemmatization(texts, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV']): texts_out = [] for sent in texts: doc = nlp(" ".join(sent)) texts_out.append([token.lemma_ for token in doc if token.pos_ in allowed_postags]) return texts_out data_words_nostops = remove_stopwords(data_words) data_words_bigrams = make_bigrams(data_words_nostops) nlp = spacy.load('en_core_web_md', disable=['parser', 'ner']) data_lemmatized = lemmatization(data_words_bigrams, allowed_postags=[ 'NOUN', 'ADJ', 'VERB', 'ADV' ]) print(data_lemmatized[:4]) #it will print the lemmatized data. id2word = corpora.Dictionary(data_lemmatized) texts = data_lemmatized corpus = [id2word.doc2bow(text) for text in texts] print(corpus[:4]) #it will print the corpus we created above. [[(id2word[id], freq) for id, freq in cp] for cp in corpus[:4]] #it will print the words with their frequencies. lda_model = gensim.models.ldamodel.LdaModel( corpus=corpus, id2word=id2word, num_topics=20, random_state=100, update_every=1, chunksize=100, passes=10, alpha='auto', per_word_topics=True )
现在我们可以使用上面创建的 LDA 模型来获取主题,以计算模型困惑度。
Gensim - 使用 LDA 主题模型
在本章中,我们将了解如何使用潜在狄利克雷分配 (LDA) 主题模型。
查看 LDA 模型中的主题
我们上面创建的 LDA 模型 (lda_model) 可用于查看文档中的主题。可以借助以下脚本完成此操作 −
pprint(lda_model.print_topics()) doc_lda = lda_model[corpus]
输出
[ (0, '0.036*"go" + 0.027*"get" + 0.021*"time" + 0.017*"back" + 0.015*"good" + ' '0.014*"much" + 0.014*"be" + 0.013*"car" + 0.013*"well" + 0.013*"year"'), (1, '0.078*"screen" + 0.067*"video" + 0.052*"character" + 0.046*"normal" + ' '0.045*"mouse" + 0.034*"manager" + 0.034*"disease" + 0.031*"processor" + ' '0.028*"excuse" + 0.028*"choice"'), (2, '0.776*"ax" + 0.079*"_" + 0.011*"boy" + 0.008*"ticket" + 0.006*"red" + ' '0.004*"conservative" + 0.004*"cult" + 0.004*"amazing" + 0.003*"runner" + ' '0.003*"roughly"'), (3, '0.086*"season" + 0.078*"fan" + 0.072*"reality" + 0.065*"trade" + ' '0.045*"concept" + 0.040*"pen" + 0.028*"blow" + 0.025*"improve" + ' '0.025*"cap" + 0.021*"penguin"'), (4, '0.027*"group" + 0.023*"issue" + 0.016*"case" + 0.016*"cause" + ' '0.014*"state" + 0.012*"whole" + 0.012*"support" + 0.011*"government" + ' '0.010*"year" + 0.010*"rate"'), (5, '0.133*"evidence" + 0.047*"believe" + 0.044*"religion" + 0.042*"belief" + ' '0.041*"sense" + 0.041*"discussion" + 0.034*"atheist" + 0.030*"conclusion" + ' '0.029*"explain" + 0.029*"claim"'), (6, '0.083*"space" + 0.059*"science" + 0.031*"launch" + 0.030*"earth" + ' '0.026*"route" + 0.024*"orbit" + 0.024*"scientific" + 0.021*"mission" + ' '0.018*"plane" + 0.017*"satellite"'), (7, '0.065*"file" + 0.064*"program" + 0.048*"card" + 0.041*"window" + ' '0.038*"driver" + 0.037*"software" + 0.034*"run" + 0.029*"machine" + ' '0.029*"entry" + 0.028*"version"'), (8, '0.078*"publish" + 0.059*"mount" + 0.050*"turkish" + 0.043*"armenian" + ' '0.027*"western" + 0.026*"russian" + 0.025*"locate" + 0.024*"proceed" + ' '0.024*"electrical" + 0.022*"terrorism"'), (9, '0.023*"people" + 0.023*"child" + 0.021*"kill" + 0.020*"man" + 0.019*"death" ' '+ 0.015*"die" + 0.015*"live" + 0.014*"attack" + 0.013*"age" + ' '0.011*"church"'), (10, '0.092*"cpu" + 0.085*"black" + 0.071*"controller" + 0.039*"white" + ' '0.028*"water" + 0.027*"cold" + 0.025*"solid" + 0.024*"cool" + 0.024*"heat" ' '+ 0.023*"nuclear"'), (11, '0.071*"monitor" + 0.044*"box" + 0.042*"option" + 0.041*"generate" + ' '0.038*"vote" + 0.032*"battery" + 0.029*"wave" + 0.026*"tradition" + ' '0.026*"fairly" + 0.025*"task"'), (12, '0.048*"send" + 0.045*"mail" + 0.036*"list" + 0.033*"include" + ' '0.032*"price" + 0.031*"address" + 0.027*"email" + 0.026*"receive" + ' '0.024*"book" + 0.024*"sell"'), (13, '0.515*"drive" + 0.052*"laboratory" + 0.042*"blind" + 0.020*"investment" + ' '0.011*"creature" + 0.010*"loop" + 0.005*"dialog" + 0.000*"slave" + ' '0.000*"jumper" + 0.000*"sector"'), (14, '0.153*"patient" + 0.066*"treatment" + 0.062*"printer" + 0.059*"doctor" + ' '0.036*"medical" + 0.031*"energy" + 0.029*"study" + 0.029*"probe" + ' '0.024*"mph" + 0.020*"physician"'), (15, '0.068*"law" + 0.055*"gun" + 0.039*"government" + 0.036*"right" + ' '0.029*"state" + 0.026*"drug" + 0.022*"crime" + 0.019*"person" + ' '0.019*"citizen" + 0.019*"weapon"'), (16, '0.107*"team" + 0.102*"game" + 0.078*"play" + 0.055*"win" + 0.052*"player" + ' '0.051*"year" + 0.030*"score" + 0.025*"goal" + 0.023*"wing" + 0.023*"run"'), (17, '0.031*"say" + 0.026*"think" + 0.022*"people" + 0.020*"make" + 0.017*"see" + ' '0.016*"know" + 0.013*"come" + 0.013*"even" + 0.013*"thing" + 0.013*"give"'), (18, '0.039*"system" + 0.034*"use" + 0.023*"key" + 0.016*"bit" + 0.016*"also" + ' '0.015*"information" + 0.014*"source" + 0.013*"chip" + 0.013*"available" + ' '0.010*"provide"'), (19, '0.085*"line" + 0.073*"write" + 0.053*"article" + 0.046*"organization" + ' '0.034*"host" + 0.023*"be" + 0.023*"know" + 0.017*"thank" + 0.016*"want" + ' '0.014*"help"') ]
计算模型困惑度
我们上面创建的 LDA 模型 (lda_model) 可用于计算模型的困惑度,即模型的好坏。分数越低,模型越好。可以使用以下脚本完成 −
print(' Perplexity: ', lda_model.log_perplexity(corpus))
输出
Perplexity: -12.338664984332151
计算一致性得分
我们上面创建的 LDA 模型 (lda_model) 可用于计算模型的一致性得分,即主题中单词的成对单词相似度得分的平均值/中位数。可以使用以下脚本完成 −
coherence_model_lda = CoherenceModel( model=lda_model, texts=data_lemmatized, dictionary=id2word, coherence='c_v' ) coherence_lda = coherence_model_lda.get_coherence() print(' Coherence Score: ', coherence_lda)
输出
Coherence Score: 0.510264381411751
可视化主题-关键词
我们上面创建的 LDA 模型 (lda_model) 可用于检查生成的主题和相关关键词。可以使用 pyLDAvis 包对其进行可视化,如下所示 −
pyLDAvis.enable_notebook() vis = pyLDAvis.gensim.prepare(lda_model, corpus, id2word) vis
输出

从上面的输出中,左侧的气泡代表一个主题,气泡越大,该主题越普遍。如果主题模型在整个图表中分布着大且不重叠的气泡,则主题模型会很好。
Gensim - 创建 LDA Mallet 模型
本章将解释什么是潜在狄利克雷分配 (LDA) Mallet 模型以及如何在 Gensim 中创建该模型。
在上一节中,我们实现了 LDA 模型并从 20Newsgroup 数据集的文档中获取主题。这是 Gensim 内置的 LDA 算法版本。Gensim 还有一个 Mallet 版本,它提供了更高质量的主题。在这里,我们将在之前已经实现的示例中应用 Mallet 的 LDA。
什么是 LDA Mallet 模型?
Mallet 是一个开源工具包,由 Andrew McCullum 编写。它基本上是一个基于 Java 的包,用于 NLP、文档分类、聚类、主题建模以及许多其他机器学习文本应用程序。它为我们提供了 Mallet 主题建模工具包,其中包含高效的、基于采样的 LDA 实现以及分层 LDA。
Mallet2.0 是 MALLET(Java 主题建模工具包)的当前版本。在开始将其与 Gensim 一起用于 LDA 之前,我们必须在系统上下载 mallet-2.0.8.zip 包并解压。安装并解压后,手动或通过我们将提供的代码将环境变量 %MALLET_HOME% 设置为指向 MALLET 目录,同时接下来使用 Mallet 实现 LDA。
Gensim 包装器
Python 为潜在狄利克雷分配 (LDA) 提供了 Gensim 包装器。该包装器的语法是 gensim.models.wrappers.LdaMallet。该模块,从 MALLET 折叠吉布斯采样,允许从训练语料库中估计 LDA 模型,并推断新文档、未见过文档的主题分布。
实施示例
我们将在之前构建的 LDA 模型上使用 LDA Mallet,并通过计算一致性分数来检查性能差异。
提供 Mallet 文件路径
在将 Mallet LDA 模型应用于上一个示例中构建的语料库之前,我们必须更新环境变量并提供 Mallet 文件的路径。可以借助以下代码完成 −
import os from gensim.models.wrappers import LdaMallet os.environ.update({'MALLET_HOME':r'C:/mallet-2.0.8/'}) #您应该根据系统上 Mallet 目录的路径更新此路径。 mallet_path = r'C:/mallet-2.0.8/bin/mallet' #您应该根据系统上 Mallet 目录的路径更新此路径。
一旦我们提供了 Mallet 文件的路径,我们现在就可以在语料库上使用它。可以借助 ldamallet.show_topics() 函数完成,如下所示 −
ldamallet = gensim.models.wrappers.LdaMallet( mallet_path, corpus=corpus, num_topics=20, id2word=id2word ) pprint(ldamallet.show_topics(formatted=False))
输出
[ (4, [('gun', 0.024546225966016102), ('law', 0.02181426826996709), ('state', 0.017633545129043606), ('people', 0.017612848479831116), ('case', 0.011341763768445888), ('crime', 0.010596684396796159), ('weapon', 0.00985160502514643), ('person', 0.008671896020034356), ('firearm', 0.00838214293105946), ('police', 0.008257963035784506)]), (9, [('make', 0.02147966482730431), ('people', 0.021377478029838543), ('work', 0.018557122419783363), ('money', 0.016676885346413244), ('year', 0.015982015123646026), ('job', 0.012221540976905783), ('pay', 0.010239117106069897), ('time', 0.008910688739014919), ('school', 0.0079092581238504), ('support', 0.007357449417535254)]), (14, [('power', 0.018428398507941996), ('line', 0.013784244460364121), ('high', 0.01183271164249895), ('work', 0.011560979224821522), ('ground', 0.010770484918850819), ('current', 0.010745781971789235), ('wire', 0.008399002000938712), ('low', 0.008053160742076529), ('water', 0.006966231071366814), ('run', 0.006892122230182061)]), (0, [('people', 0.025218349201353372), ('kill', 0.01500904870564167), ('child', 0.013612400660948935), ('armenian', 0.010307655991816822), ('woman', 0.010287984892595798), ('start', 0.01003226060272248), ('day', 0.00967818081674404), ('happen', 0.009383114328428673), ('leave', 0.009383114328428673), ('fire', 0.009009363443229208)]), (1, [('file', 0.030686386604212003), ('program', 0.02227713642901929), ('window', 0.01945561169918489), ('set', 0.015914874783314277), ('line', 0.013831003577619592), ('display', 0.013794120901412606), ('application', 0.012576992586582082), ('entry', 0.009275993066056873), ('change', 0.00872275292295209), ('color', 0.008612104894331132)]), (12, [('line', 0.07153810971508515), ('buy', 0.02975597944523662), ('organization', 0.026877236406682988), ('host', 0.025451316957679788), ('price', 0.025182275552207485), ('sell', 0.02461728860071565), ('mail', 0.02192687454599263), ('good', 0.018967419085797303), ('sale', 0.017998870026097017), ('send', 0.013694207538540181)]), (11, [('thing', 0.04901329901329901), ('good', 0.0376018876018876), ('make', 0.03393393393393394), ('time', 0.03326898326898327), ('bad', 0.02664092664092664), ('happen', 0.017696267696267698), ('hear', 0.015615615615615615), ('problem', 0.015465465465465466), ('back', 0.015143715143715144), ('lot', 0.01495066495066495)]), (18, [('space', 0.020626317374284855), ('launch', 0.00965716006366413), ('system', 0.008560244332602057), ('project', 0.008173097603991913), ('time', 0.008108573149223556), ('cost', 0.007764442723792318), ('year', 0.0076784101174345075), ('earth', 0.007484836753129436), ('base', 0.0067535595990880545), ('large', 0.006689035144319697)]), (5, [('government', 0.01918437232469453), ('people', 0.01461203206475212), ('state', 0.011207097828624796), ('country', 0.010214802708381975), ('israeli', 0.010039691804809714), ('war', 0.009436532025838587), ('force', 0.00858043427504086), ('attack', 0.008424780138532182), ('land', 0.0076659662230523775), ('world', 0.0075103120865437)]), (2, [('car', 0.041091194044470564), ('bike', 0.015598981291017729), ('ride', 0.011019688510138114), ('drive', 0.010627877363110981), ('engine', 0.009403467528651191), ('speed', 0.008081104907434616), ('turn', 0.007738270153785875), ('back', 0.007738270153785875), ('front', 0.007468899990204721), ('big', 0.007370947203447938)]) ]
评估性能
现在我们还可以通过计算一致性得分来评估其性能,如下所示 −
ldamallet = gensim.models.wrappers.LdaMallet( mallet_path, corpus=corpus, num_topics=20, id2word=id2word ) pprint(ldamallet.show_topics(formatted=False))
输出
Coherence Score: 0.5842762900901401
Gensim - 文档和 LDA 模型
本章讨论 Gensim 中的文档和 LDA 模型。
寻找 LDA 的最佳主题数量
我们可以通过创建具有各种主题值的多个 LDA 模型来寻找 LDA 的最佳主题数量。在这些 LDA 中,我们可以选择一个具有最高一致性值的模型。
以下名为 coherence_values_computation() 的函数将训练多个 LDA 模型。它还将提供模型及其相应的一致性分数 −
def coherence_values_computation(dictionary, corpus, texts, limit, start=2, step=3): coherence_values = [] model_list = [] for num_topics in range(start, limit, step): model = gensim.models.wrappers.LdaMallet( mallet_path, corpus=corpus, num_topics=num_topics, id2word=id2word ) model_list.append(model) coherencemodel = CoherenceModel( model=model, texts=texts, dictionary=dictionary, coherence='c_v' ) coherence_values.append(coherencemodel.get_coherence()) return model_list, coherence_values
现在借助以下代码,我们可以得到最佳主题数量,并借助图表显示这些主题数量 −
model_list, coherence_values = coherence_values_computation ( dictionary=id2word, corpus=corpus, texts=data_lemmatized, start=1, limit=50, step=8 ) limit=50; start=1; step=8; x = range(start, limit, step) plt.plot(x, coherence_values) plt.xlabel("Num Topics") plt.ylabel("Coherence score") plt.legend(("coherence_values"), loc='best') plt.show()
输出

接下来,我们还可以打印各种主题的连贯性值,如下所示 −
for m, cv in zip(x, coherence_values): print("Num Topics =", m, " is having Coherence Value of", round(cv, 4))
输出
Num Topics = 1 is having Coherence Value of 0.4866 Num Topics = 9 is having Coherence Value of 0.5083 Num Topics = 17 is having Coherence Value of 0.5584 Num Topics = 25 is having Coherence Value of 0.5793 Num Topics = 33 is having Coherence Value of 0.587 Num Topics = 41 is having Coherence Value of 0.5842 Num Topics = 49 is having Coherence Value of 0.5735
现在,问题来了,我们现在应该选择哪个模型?一个好的做法是,先选择连贯性值最高的模型,然后再进行讨好。因此,我们将选择上面列表中排名第 4 的包含 25 个主题的模型。
optimal_model = model_list[3] model_topics = optimal_model.show_topics(formatted=False) pprint(optimal_model.print_topics(num_words=10)) [ (0, '0.018*"power" + 0.011*"high" + 0.010*"ground" + 0.009*"current" + ' '0.008*"low" + 0.008*"wire" + 0.007*"water" + 0.007*"work" + 0.007*"design" ' '+ 0.007*"light"'), (1, '0.036*"game" + 0.029*"team" + 0.029*"year" + 0.028*"play" + 0.020*"player" ' '+ 0.019*"win" + 0.018*"good" + 0.013*"season" + 0.012*"run" + 0.011*"hit"'), (2, '0.020*"image" + 0.019*"information" + 0.017*"include" + 0.017*"mail" + ' '0.016*"send" + 0.015*"list" + 0.013*"post" + 0.012*"address" + ' '0.012*"internet" + 0.012*"system"'), (3, '0.986*"ax" + 0.002*"_" + 0.001*"tm" + 0.000*"part" + 0.000*"biz" + ' '0.000*"mb" + 0.000*"mbs" + 0.000*"pne" + 0.000*"end" + 0.000*"di"'), (4, '0.020*"make" + 0.014*"work" + 0.013*"money" + 0.013*"year" + 0.012*"people" ' '+ 0.011*"job" + 0.010*"group" + 0.009*"government" + 0.008*"support" + ' '0.008*"question"'), (5, '0.011*"study" + 0.011*"drug" + 0.009*"science" + 0.008*"food" + ' '0.008*"problem" + 0.008*"result" + 0.008*"effect" + 0.007*"doctor" + ' '0.007*"research" + 0.007*"patient"'), (6, '0.024*"gun" + 0.024*"law" + 0.019*"state" + 0.015*"case" + 0.013*"people" + ' '0.010*"crime" + 0.010*"weapon" + 0.010*"person" + 0.008*"firearm" + ' '0.008*"police"'), (7, '0.012*"word" + 0.011*"question" + 0.011*"exist" + 0.011*"true" + ' '0.010*"religion" + 0.010*"claim" + 0.008*"argument" + 0.008*"truth" + ' '0.008*"life" + 0.008*"faith"'), (8, '0.077*"time" + 0.029*"day" + 0.029*"call" + 0.025*"back" + 0.021*"work" + ' '0.019*"long" + 0.015*"end" + 0.015*"give" + 0.014*"year" + 0.014*"week"'), (9, '0.048*"thing" + 0.041*"make" + 0.038*"good" + 0.037*"people" + ' '0.028*"write" + 0.019*"bad" + 0.019*"point" + 0.018*"read" + 0.018*"post" + ' '0.016*"idea"'), (10, '0.022*"book" + 0.020*"_" + 0.013*"man" + 0.012*"people" + 0.011*"write" + ' '0.011*"find" + 0.010*"history" + 0.010*"armenian" + 0.009*"turkish" + ' '0.009*"number"'), (11, '0.064*"line" + 0.030*"buy" + 0.028*"organization" + 0.025*"price" + ' '0.025*"sell" + 0.023*"good" + 0.021*"host" + 0.018*"sale" + 0.017*"mail" + ' '0.016*"cost"'), (12, '0.041*"car" + 0.015*"bike" + 0.011*"ride" + 0.010*"engine" + 0.009*"drive" ' '+ 0.008*"side" + 0.008*"article" + 0.007*"turn" + 0.007*"front" + ' '0.007*"speed"'), (13, '0.018*"people" + 0.011*"attack" + 0.011*"state" + 0.011*"israeli" + ' '0.010*"war" + 0.010*"country" + 0.010*"government" + 0.009*"live" + ' '0.009*"give" + 0.009*"land"'), (14, '0.037*"file" + 0.026*"line" + 0.021*"read" + 0.019*"follow" + ' '0.018*"number" + 0.015*"program" + 0.014*"write" + 0.012*"entry" + ' '0.012*"give" + 0.011*"check"'), (15, '0.196*"write" + 0.172*"line" + 0.165*"article" + 0.117*"organization" + ' '0.086*"host" + 0.030*"reply" + 0.010*"university" + 0.008*"hear" + ' '0.007*"post" + 0.007*"news"'), (16, '0.021*"people" + 0.014*"happen" + 0.014*"child" + 0.012*"kill" + ' '0.011*"start" + 0.011*"live" + 0.010*"fire" + 0.010*"leave" + 0.009*"hear" ' '+ 0.009*"home"'), (17, '0.038*"key" + 0.018*"system" + 0.015*"space" + 0.015*"technology" + ' '0.014*"encryption" + 0.010*"chip" + 0.010*"bit" + 0.009*"launch" + ' '0.009*"public" + 0.009*"government"'), (18, '0.035*"drive" + 0.031*"system" + 0.027*"problem" + 0.027*"card" + ' '0.020*"driver" + 0.017*"bit" + 0.017*"work" + 0.016*"disk" + ' '0.014*"monitor" + 0.014*"machine"'), (19, '0.031*"window" + 0.020*"run" + 0.018*"color" + 0.018*"program" + ' '0.017*"application" + 0.016*"display" + 0.015*"set" + 0.015*"version" + ' '0.012*"screen" + 0.012*"problem"') ]
在句子中查找主导主题
在句子中查找主导主题是主题建模最有用的实际应用之一。它确定给定文档的主题。在这里,我们将找到在该特定文档中贡献百分比最高的主题编号。为了将信息汇总到表中,我们将创建一个名为 dominant_topics() −
的函数def modest_topics(ldamodel=lda_model, corpus=corpus, texts=data): sent_topics_df = pd.DataFrame()
接下来,我们将获取每个文档中的主要主题 −
for i, row in enumerate(ldamodel[corpus]): row = sorted(row, key=lambda x: (x[1]), reverse=True)
接下来,我们将获取每个文档的主导主题、Perc 贡献和关键字 −
for j, (topic_num, prop_topic) in enumerate(row): if j == 0: # => dominant topic wp = ldamodel.show_topic(topic_num) topic_keywords = ", ".join([word for word, prop in wp]) sent_topics_df = sent_topics_df.append( pd.Series([int(topic_num), round(prop_topic,4), topic_keywords]), ignore_index=True ) else: break sent_topics_df.columns = ['Dominant_Topic', 'Perc_Contribution', 'Topic_Keywords']
借助以下代码,我们将原始文本添加到输出的末尾 −
contents = pd.Series(texts) sent_topics_df = pd.concat([sent_topics_df, contents], axis=1) return(sent_topics_df) df_topic_sents_keywords = dominant_topics( ldamodel=optimal_model, corpus=corpus, texts=data )
现在,对句子中的主题进行如下格式化 −
df_dominant_topic = df_topic_sents_keywords.reset_index() df_dominant_topic.columns = [ 'Document_No', 'Dominant_Topic', 'Topic_Perc_Contrib', 'Keywords', 'Text' ]
最后,我们可以按如下方式显示主导主题 −
df_dominant_topic.head(15)

查找最具代表性的文档
为了更多地了解该主题,我们还可以找到给定主题贡献最大的文档。我们可以通过阅读该特定文档来推断该主题。
sent_topics_sorteddf_mallet = pd.DataFrame() sent_topics_outdf_grpd = df_topic_sents_keywords.groupby('Dominant_Topic') for i, grp in sent_topics_outdf_grpd: sent_topics_sorteddf_mallet = pd.concat([sent_topics_sorteddf_mallet, grp.sort_values(['Perc_Contribution'], ascending=[0]).head(1)], axis=0) sent_topics_sorteddf_mallet.reset_index(drop=True, inplace=True) sent_topics_sorteddf_mallet.columns = [ 'Topic_Number', "Contribution_Perc", "Keywords", "Text" ] sent_topics_sorteddf_mallet.head()
输出

主题的数量和分布
有时我们还想判断文档中讨论主题的广泛程度。为此,我们需要了解文档中主题的数量和分布情况。
首先计算每个主题的文档数量,如下所示 −
topic_counts = df_topic_sents_keywords['Dominant_Topic'].value_counts()
接下来,计算每个主题的文档百分比,如下所示 −;
topic_contribution = round(topic_counts/topic_counts.sum(), 4)
现在找到主题数量和关键字,如下所示 −
topic_num_keywords = df_topic_sents_keywords[['Dominant_Topic', 'Topic_Keywords']]
现在,按列连接,如下所示 −
df_dominant_topics = pd.concat( [topic_num_keywords, topic_counts, topic_contribution], axis=1 )
接下来,我们将更改列名称,如下所示 −
df_dominant_topics.columns = [ 'Dominant-Topic', 'Topic-Keywords', 'Num_Documents', 'Perc_Documents' ] df_dominant_topics
输出

Gensim - 创建 LSI 和 HDP 主题模型
本章介绍如何创建与 Gensim 相关的潜在语义索引 (LSI) 和分层狄利克雷过程 (HDP) 主题模型。
Gensim 中首次使用潜在狄利克雷分配 (LDA) 实现的主题建模算法是潜在语义索引 (LSI)。它也被称为潜在语义分析 (LSA)。它于 1988 年由 Scott Deerwester、Susan Dumais、George Furnas、Richard Harshman、Thomas Landaur、Karen Lochbaum 和 Lynn Streeter 获得专利。
在本节中,我们将设置我们的 LSI 模型。它可以采用与设置 LDA 模型相同的方式完成。我们需要从 gensim.models 导入 LSI 模型。
LSI 的作用
实际上,LSI 是一种 NLP 技术,尤其是在分布式语义方面。它分析一组文档与这些文档包含的术语之间的关系。如果我们谈论它的工作原理,那么它会从大量文本中构建一个包含每个文档的字数的矩阵。
构建后,为了减少行数,LSI 模型使用一种称为奇异值分解 (SVD) 的数学技术。除了减少行数外,它还保留了列之间的相似性结构。
在矩阵中,行代表唯一的单词,列代表每个文档。它基于分布假设,即假设含义相近的单词会出现在同一类文本中。
使用 Gensim 实现
在这里,我们将使用 LSI(潜在语义索引)从数据集中提取自然讨论的主题。
加载数据集
我们将要使用的数据集是 '20 个新闻组' 的数据集,其中包含来自新闻报道各个部分的数千篇新闻文章。它可在 Sklearn 数据集下找到。我们可以通过以下 Python 脚本轻松下载 −
from sklearn.datasets import fetch_20newsgroups newsgroups_train = fetch_20newsgroups(subset='train')
让我们通过以下脚本查看一些示例新闻 −
newsgroups_train.data[:4] ["From: lerxst@wam.umd.edu (where's my thing) Subject: WHAT car is this!? Nntp-Posting-Host: rac3.wam.umd.edu Organization: University of Maryland, College Park Lines: 15 I was wondering if anyone out there could enlighten me on this car I saw the other day. It was a 2-door sports car, looked to be from the late 60s/ early 70s. It was called a Bricklin. The doors were really small. In addition, the front bumper was separate from the rest of the body. This is all I know. If anyone can tellme a model name, engine specs, years of production, where this car is made, history, or whatever info you have on this funky looking car, please e-mail. Thanks, - IL ---- brought to you by your neighborhood Lerxst ---- ", "From: guykuo@carson.u.washington.edu (Guy Kuo) Subject: SI Clock Poll - Final Call Summary: Final call for SI clock reports Keywords: SI,acceleration,clock,upgrade Article-I.D.: shelley.1qvfo9INNc3s Organization: University of Washington Lines: 11 NNTP-Posting-Host: carson.u.washington.edu A fair number of brave souls who upgraded their SI clock oscillator have shared their experiences for this poll. Please send a brief message detailing your experiences with the procedure. Top speed attained, CPU rated speed, add on cards and adapters, heat sinks, hour of usage per day, floppy disk functionality with 800 and 1.4 m floppies are especially requested. I will be summarizing in the next two days, so please add to the network knowledge base if you have done the clock upgrade and haven't answered this poll. Thanks. Guy Kuo <guykuo@u.washington.edu> ", 'From: twillis@ec.ecn.purdue.edu (Thomas E Willis) Subject: PB questions... Organization: Purdue University Engineering Computer Network Distribution: usa Lines: 36 well folks, my mac plus finally gave up the ghost this weekend after starting life as a 512k way back in 1985. sooo, i\'m in the market for a new machine a bit sooner than i intended to be... i\'m looking into picking up a powerbook 160 or maybe 180 and have a bunch of questions that (hopefully) somebody can answer: * does anybody know any dirt on when the next round of powerbook introductions are expected? i\'d heard the 185c was supposed to make an appearence "this summer" but haven\'t heard anymore on it - and since i don\'t have access to macleak, i was wondering if anybody out there had more info... * has anybody heard rumors about price drops to the powerbook line like the ones the duo\'s just went through recently? * what\'s the impression of the display on the 180? i could probably swing a 180 if i got the 80Mb disk rather than the 120, but i don\'t really have a feel for how much "better" the display is (yea, it looks great in the store, but is that all "wow" or is it really that good?). could i solicit some opinions of people who use the 160 and 180 day-to-day on if its worth taking the disk size and money hit to get the active display? (i realize this is a real subjective question, but i\'ve only played around with the machines in a computer store breifly and figured the opinions of somebody who actually uses the machine daily might prove helpful). * how well does hellcats perform? ;) thanks a bunch in advance for any info - if you could email, i\'ll post a summary (news reading time is at a premium with finals just around the corner... :( ) -- Tom Willis \ twillis@ecn.purdue.edu \ Purdue Electrical Engineering ---------------------------------------------------------------------------\ n"Convictions are more dangerous enemies of truth than lies." - F. W. Nietzsche ', 'From: jgreen@amber (Joe Green) Subject: Re: Weitek P9000 ? Organization: Harris Computer Systems Division Lines: 14 Distribution: world NNTP-Posting-Host: amber.ssd.csd.harris.com X-Newsreader: TIN [version 1.1 PL9] Robert J.C. Kyanko (rob@rjck.UUCP) wrote: > abraxis@iastate.edu writes in article < abraxis.734340159@class1.iastate.edu>: > > Anyone know about the Weitek P9000 graphics chip? > As far as the low-level stuff goes, it looks pretty nice. It\'s got this > quadrilateral fill command that requires just the four points. Do you have Weitek\'s address/phone number? I\'d like to get some information about this chip. -- Joe Green Harris Corporation jgreen@csd.harris.com Computer Systems Division "The only thing that really scares me is a person with no sense of humor." -- Jonathan Winters ']
先决条件
我们需要 NLTK 中的停用词和 Scapy 中的英语模型。两者都可以通过以下方式下载 −
import nltk; nltk.download('stopwords') nlp = spacy.load('en_core_web_md', disable=['parser', 'ner'])
导入必要的包
为了构建 LSI 模型,我们需要导入以下必要的包 −
import re import numpy as np import pandas as pd from pprint import pprint import gensim import gensim.corpora as corpora from gensim.utils import simple_preprocess from gensim.models import CoherenceModel import spacy import matplotlib.pyplot as plt
准备停用词
现在我们需要导入停用词并使用它们 −
from nltk.corpus import stopwords stop_words = stopwords.words('english') stop_words.extend(['from', 'subject', 're', 'edu', 'use'])
清理文本
现在,借助 Gensim 的 simple_preprocess(),我们需要将每个句子标记为一个单词列表。我们还应该删除标点符号和不必要的字符。为了做到这一点,我们将创建一个名为 sent_to_words() 的函数 −
def sent_to_words(sentences): for sentence in sentences: yield(gensim.utils.simple_preprocess(str(sentence), deacc=True)) data_words = list(sent_to_words(data))
构建二元词组和三元词组模型
众所周知,二元词组是文档中经常一起出现的两个单词,而三元词组是文档中经常一起出现的三个单词。借助 Gensim 的短语模型,我们可以做到这一点 −
bigram = gensim.models.Phrases(data_words, min_count=5, Threshold=100) trigram = gensim.models.Phrases(bigram[data_words], Threshold=100) bigram_mod = gensim.models.phrases.Phraser(bigram) trigram_mod = gensim.models.phrases.Phraser(trigram)
过滤掉停用词
接下来,我们需要过滤掉停用词。除此之外,我们还将创建用于制作二元组、三元组和词形还原的函数 −
def remove_stopwords(texts): return [[word for word in simple_preprocess(str(doc)) if word not in stop_words] for doc in texts] def make_bigrams(texts): return [bigram_mod[doc] for doc in texts] def make_trigrams(texts): return [trigram_mod[bigram_mod[doc]] for doc in texts] def lemmatization(texts, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV']): texts_out = [] for sent in texts: doc = nlp(" ".join(sent)) texts_out.append([token.lemma_ for token in doc if token.pos_ in allowed_postags]) return texts_out
为主题模型构建词典和语料库
现在我们需要构建词典和语料库。我们在前面的例子中也做过 −
id2word = corpora.Dictionary(data_lemmatized) texts = data_lemmatized corpus = [id2word.doc2bow(text) for text in texts]
构建 LSI 主题模型
我们已经实现了训练 LSI 模型所需的一切。现在是时候构建 LSI 主题模型了。对于我们的实现示例,可以借助以下代码行完成 −
lsi_model = gensim.models.lsimodel.LsiModel( corpus=corpus, id2word=id2word, num_topics=20,chunksize=100 )
实现示例
让我们看看构建 LDA 主题模型的完整实现示例 −
import re import numpy as np import pandas as pd from pprint import pprint import gensim import gensim.corpora as corpora from gensim.utils import simple_preprocess from gensim.models import CoherenceModel import spacy import matplotlib.pyplot as plt from nltk.corpus import stopwords stop_words = stopwords.words('english') stop_words.extend(['from', 'subject', 're', 'edu', 'use']) from sklearn.datasets import fetch_20newsgroups newsgroups_train = fetch_20newsgroups(subset='train') data = newsgroups_train.data data = [re.sub('\S*@\S*\s?', '', sent) for sent in data] data = [re.sub('\s+', ' ', sent) for sent in data] data = [re.sub("\'", "", sent) for sent in data] print(data_words[:4]) #it will print the data after prepared for stopwords bigram = gensim.models.Phrases(data_words, min_count=5, threshold=100) trigram = gensim.models.Phrases(bigram[data_words], threshold=100) bigram_mod = gensim.models.phrases.Phraser(bigram) trigram_mod = gensim.models.phrases.Phraser(trigram) def remove_stopwords(texts): return [[word for word in simple_preprocess(str(doc)) if word not in stop_words] for doc in texts] def make_bigrams(texts): return [bigram_mod[doc] for doc in texts] def make_trigrams(texts): return [trigram_mod[bigram_mod[doc]] for doc in texts] def lemmatization(texts, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV']): texts_out = [] for sent in texts: doc = nlp(" ".join(sent)) texts_out.append([token.lemma_ for token in doc if token.pos_ in allowed_postags]) return texts_out data_words_nostops = remove_stopwords(data_words) data_words_bigrams = make_bigrams(data_words_nostops) nlp = spacy.load('en_core_web_md', disable=['parser', 'ner']) data_lemmatized = lemmatization( data_words_bigrams, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV'] ) print(data_lemmatized[:4]) #it will print the lemmatized data. id2word = corpora.Dictionary(data_lemmatized) texts = data_lemmatized corpus = [id2word.doc2bow(text) for text in texts] print(corpus[:4]) #it will print the corpus we created above. [[(id2word[id], freq) for id, freq in cp] for cp in corpus[:4]] #it will print the words with their frequencies. lsi_model = gensim.models.lsimodel.LsiModel( corpus=corpus, id2word=id2word, num_topics=20,chunksize=100 )
现在我们可以使用上面创建的 LSI 模型来获取主题。
查看 LSI 模型中的主题
我们上面创建的 LSI 模型 (lsi_model) 可用于查看文档中的主题。可以借助以下脚本完成此操作 −
pprint(lsi_model.print_topics()) doc_lsi = lsi_model[corpus]
输出
[ (0, '1.000*"ax" + 0.001*"_" + 0.000*"tm" + 0.000*"part" + 0.000*"pne" + ' '0.000*"biz" + 0.000*"mbs" + 0.000*"end" + 0.000*"fax" + 0.000*"mb"'), (1, '0.239*"say" + 0.222*"file" + 0.189*"go" + 0.171*"know" + 0.169*"people" + ' '0.147*"make" + 0.140*"use" + 0.135*"also" + 0.133*"see" + 0.123*"think"') ]
分层狄利克雷过程 (HPD)
LDA 和 LSI 等主题模型有助于总结和组织无法手动分析的大量文本档案。除了 LDA 和 LSI,Gensim 中另一个强大的主题模型是 HDP(分层狄利克雷过程)。它基本上是一个用于无监督分析分组数据的混合成员模型。与 LDA(其有限对应物)不同,HDP 从数据中推断出主题数量。
使用 Gensim 实现
为了在 Gensim 中实现 HDP,我们需要训练语料库和词典(如上例中在实现 LDA 和 LSI 主题模型时所做的那样)我们可以从 gensim.models.HdpModel 导入 HDP 主题模型。这里我们也将在 20Newsgroup 数据上实现 HDP 主题模型,步骤也相同。
对于我们的语料库和词典(在上面的 LSI 和 LDA 模型示例中创建),我们可以按如下方式导入 HdpModel −
Hdp_model = gensim.models.hdpmodel.HdpModel(corpus=corpus, id2word=id2word)
查看 LSI 模型中的主题
HDP 模型 (Hdp_model) 可用于查看文档中的主题。可以借助以下脚本完成此操作 −
pprint(Hdp_model.print_topics())
输出
[ (0, '0.009*line + 0.009*write + 0.006*say + 0.006*article + 0.006*know + ' '0.006*people + 0.005*make + 0.005*go + 0.005*think + 0.005*be'), (1, '0.016*line + 0.011*write + 0.008*article + 0.008*organization + 0.006*know ' '+ 0.006*host + 0.006*be + 0.005*get + 0.005*use + 0.005*say'), (2, '0.810*ax + 0.001*_ + 0.000*tm + 0.000*part + 0.000*mb + 0.000*pne + ' '0.000*biz + 0.000*end + 0.000*wwiz + 0.000*fax'), (3, '0.015*line + 0.008*write + 0.007*organization + 0.006*host + 0.006*know + ' '0.006*article + 0.005*use + 0.005*thank + 0.004*get + 0.004*problem'), (4, '0.004*line + 0.003*write + 0.002*believe + 0.002*think + 0.002*article + ' '0.002*belief + 0.002*say + 0.002*see + 0.002*look + 0.002*organization'), (5, '0.005*line + 0.003*write + 0.003*organization + 0.002*article + 0.002*time ' '+ 0.002*host + 0.002*get + 0.002*look + 0.002*say + 0.001*number'), (6, '0.003*line + 0.002*say + 0.002*write + 0.002*go + 0.002*gun + 0.002*get + ' '0.002*organization + 0.002*bill + 0.002*article + 0.002*state'), (7, '0.003*line + 0.002*write + 0.002*article + 0.002*organization + 0.001*none ' '+ 0.001*know + 0.001*say + 0.001*people + 0.001*host + 0.001*new'), (8, '0.004*line + 0.002*write + 0.002*get + 0.002*team + 0.002*organization + ' '0.002*go + 0.002*think + 0.002*know + 0.002*article + 0.001*well'), (9, '0.004*line + 0.002*organization + 0.002*write + 0.001*be + 0.001*host + ' '0.001*article + 0.001*thank + 0.001*use + 0.001*work + 0.001*run'), (10, '0.002*line + 0.001*game + 0.001*write + 0.001*get + 0.001*know + ' '0.001*thing + 0.001*think + 0.001*article + 0.001*help + 0.001*turn'), (11, '0.002*line + 0.001*write + 0.001*game + 0.001*organization + 0.001*say + ' '0.001*host + 0.001*give + 0.001*run + 0.001*article + 0.001*get'), (12, '0.002*line + 0.001*write + 0.001*know + 0.001*time + 0.001*article + ' '0.001*get + 0.001*think + 0.001*organization + 0.001*scope + 0.001*make'), (13, '0.002*line + 0.002*write + 0.001*article + 0.001*organization + 0.001*make ' '+ 0.001*know + 0.001*see + 0.001*get + 0.001*host + 0.001*really'), (14, '0.002*write + 0.002*line + 0.002*know + 0.001*think + 0.001*say + ' '0.001*article + 0.001*argument + 0.001*even + 0.001*card + 0.001*be'), (15, '0.001*article + 0.001*line + 0.001*make + 0.001*write + 0.001*know + ' '0.001*say + 0.001*exist + 0.001*get + 0.001*purpose + 0.001*organization'), (16, '0.002*line + 0.001*write + 0.001*article + 0.001*insurance + 0.001*go + ' '0.001*be + 0.001*host + 0.001*say + 0.001*organization + 0.001*part'), (17, '0.001*line + 0.001*get + 0.001*hit + 0.001*go + 0.001*write + 0.001*say + ' '0.001*know + 0.001*drug + 0.001*see + 0.001*need'), (18, '0.002*option + 0.001*line + 0.001*flight + 0.001*power + 0.001*software + ' '0.001*write + 0.001*add + 0.001*people + 0.001*organization + 0.001*module'), (19, '0.001*shuttle + 0.001*line + 0.001*roll + 0.001*attitude + 0.001*maneuver + ' '0.001*mission + 0.001*also + 0.001*orbit + 0.001*produce + 0.001*frequency') ]
Gensim - 开发词嵌入
本章将帮助我们理解在 Gensim 中开发词嵌入。
词嵌入是一种表示单词和文档的方法,它是一种文本的密集向量表示,其中具有相同含义的单词具有相似的表示。以下是词嵌入的一些特点 −
这是一类将单个单词表示为预定义向量空间中的实值向量的技术。
这种技术通常被归入 DL(深度学习)领域,因为每个单词都映射到一个向量,并且向量值的学习方式与 NN(神经网络)相同。
词嵌入技术的关键方法是为每个单词提供密集的分布式表示。
不同的词嵌入方法/算法
如上所述,词嵌入方法/算法从文本语料库中学习实值向量表示。此学习过程既可以与 NN 模型一起用于文档分类等任务,也可以是文档统计等无监督过程。这里我们将讨论两种可用于从文本中学习词嵌入的方法/算法 −
Google 的 Word2Vec
Word2Vec 由 Tomas Mikolov 等人于 2013 年在 Google 开发,是一种用于从文本语料库中高效学习词嵌入的统计方法。它实际上是为了使基于 NN 的词嵌入训练更加高效而开发的。它已成为词嵌入的事实标准。
Word2Vec 的词嵌入涉及对学习到的向量的分析以及对词表示的向量数学的探索。以下是两种不同的学习方法,可用作 Word2Vec 方法的一部分 −
- CBoW(连续词袋)模型
- 连续 Skip-Gram 模型
斯坦福的 GloVe
GloVe(用于词表示的全局向量)是 Word2Vec 方法的扩展。它由斯坦福的 Pennington 等人开发。 GloVe 算法是两者的混合体 −
- 矩阵分解技术(如 LSA(潜在语义分析))的全局统计数据
- Word2Vec 中的基于局部上下文的学习。
如果我们谈论它的工作原理,那么 GloVe 不是使用窗口来定义局部上下文,而是使用整个文本语料库的统计数据构建一个明确的单词共现矩阵。
开发 Word2Vec 嵌入
在这里,我们将使用 Gensim 开发 Word2Vec 嵌入。为了使用 Word2Vec 模型,Gensim 为我们提供了 Word2Vec 类,可以从 models.word2vec 导入。为了实现它,word2vec 需要大量文本,例如整个亚马逊评论语料库。但在这里,我们将把这个原则应用于内存中的小文本。
实施示例
首先,我们需要从 gensim.models 导入 Word2Vec 类,如下所示 −
from gensim.models import Word2Vec
接下来,我们需要定义训练数据。我们不是使用大文本文件,而是使用一些句子来实现这个原则。
sentences = [ ['this', 'is', 'gensim', 'tutorial', 'for', 'free'], ['this', 'is', 'the', 'tutorials' 'point', 'website'], ['you', 'can', 'read', 'technical','tutorials', 'for','free'], ['we', 'are', 'implementing','word2vec'], ['learn', 'full', 'gensim', 'tutorial'] ]
一旦提供了训练数据,我们就需要训练模型。可以按如下方式完成 −
model = Word2Vec(sentences, min_count=1)
我们可以按如下方式总结模型 −;
print(model)
我们可以按如下方式总结词汇表 −
words = list(model.wv.vocab) print(words)
接下来,让我们访问一个单词的向量。我们正在针对单词"tutorial"执行此操作。
print(model['tutorial'])
接下来,我们需要保存模型 −
model.save('model.bin')
接下来,我们需要加载模型 −
new_model = Word2Vec.load('model.bin')
最后,打印保存的模型如下 −
print(new_model)
完整实现示例
from gensim.models import Word2Vec sentences = [ ['this', 'is', 'gensim', 'tutorial', 'for', 'free'], ['this', 'is', 'the', 'tutorials' 'point', 'website'], ['you', 'can', 'read', 'technical','tutorials', 'for','free'], ['we', 'are', 'implementing','word2vec'], ['learn', 'full', 'gensim', 'tutorial'] ] model = Word2Vec(sentences, min_count=1) print(model) words = list(model.wv.vocab) print(words) print(model['tutorial']) model.save('model.bin') new_model = Word2Vec.load('model.bin') print(new_model)
输出
Word2Vec(vocab=20, size=100, alpha=0.025) [ 'this', 'is', 'gensim', 'tutorial', 'for', 'free', 'the', 'tutorialspoint', 'website', 'you', 'can', 'read', 'technical', 'tutorials', 'we', 'are', 'implementing', 'word2vec', 'learn', 'full' ] [ -2.5256255e-03 -4.5352755e-03 3.9024993e-03 -4.9509313e-03 -1.4255195e-03 -4.0217536e-03 4.9407515e-03 -3.5925603e-03 -1.1933431e-03 -4.6682903e-03 1.5440651e-03 -1.4101702e-03 3.5070938e-03 1.0914479e-03 2.3334436e-03 2.4452661e-03 -2.5336299e-04 -3.9676363e-03 -8.5054158e-04 1.6443320e-03 -4.9968651e-03 1.0974540e-03 -1.1123562e-03 1.5393364e-03 9.8941079e-04 -1.2656028e-03 -4.4471184e-03 1.8309267e-03 4.9302122e-03 -1.0032534e-03 4.6892050e-03 2.9563988e-03 1.8730218e-03 1.5343715e-03 -1.2685956e-03 8.3664013e-04 4.1721235e-03 1.9445885e-03 2.4097660e-03 3.7517555e-03 4.9687522e-03 -1.3598346e-03 7.1032363e-04 -3.6595813e-03 6.0000515e-04 3.0872561e-03 -3.2115565e-03 3.2270295e-03 -2.6354722e-03 -3.4988276e-04 1.8574356e-04 -3.5757164e-03 7.5391348e-04 -3.5205986e-03 -1.9795434e-03 -2.8321696e-03 4.7155009e-03 -4.3349937e-04 -1.5320212e-03 2.7013756e-03 -3.7055744e-03 -4.1658725e-03 4.8034848e-03 4.8594419e-03 3.7129463e-03 4.2385766e-03 2.4612297e-03 5.4920948e-04 -3.8912550e-03 -4.8226118e-03 -2.2763973e-04 4.5571579e-03 -3.4609400e-03 2.7903817e-03 -3.2709218e-03 -1.1036445e-03 2.1492650e-03 -3.0384419e-04 1.7709908e-03 1.8429896e-03 -3.4038599e-03 -2.4872608e-03 2.7693063e-03 -1.6352943e-03 1.9182395e-03 3.7772327e-03 2.2769428e-03 -4.4629495e-03 3.3151123e-03 4.6509290e-03 -4.8521687e-03 6.7615538e-04 3.1034781e-03 2.6369948e-05 4.1454583e-03 -3.6932561e-03 -1.8769916e-03 -2.1958587e-04 6.3395966e-04 -2.4969708e-03 ] Word2Vec(vocab=20, size=100, alpha=0.025)
可视化词向量
我们还可以通过可视化探索词向量。可以使用经典投影方法(如 PCA)将高维词向量简化为二维图。一旦简化,我们就可以将它们绘制在图表上。
使用 PCA 绘制词向量
首先,我们需要从训练模型中检索所有向量,如下所示 −
Z = model[model.wv.vocab]
接下来,我们需要使用 PCA 类创建词向量的 2-D PCA 模型,如下所示 −
pca = PCA(n_components=2) result = pca.fit_transform(Z)
现在,我们可以使用 matplotlib 绘制结果投影,如下所示 −
Pyplot.scatter(result[:,0],result[:,1])
我们还可以在图表上注释点用单词本身来表示。使用 matplotlib 绘制结果投影,如下所示−
words = list(model.wv.vocab) for i, word in enumerate(words): pyplot.annotate(word, xy=(result[i, 0], result[i, 1]))
完整实现示例
from gensim.models import Word2Vec from sklearn.decomposition import PCA from matplotlib import pyplot sentences = [ ['this', 'is', 'gensim', 'tutorial', 'for', 'free'], ['this', 'is', 'the', 'tutorials' 'point', 'website'], ['you', 'can', 'read', 'technical','tutorials', 'for','free'], ['we', 'are', 'implementing','word2vec'], ['learn', 'full', 'gensim', 'tutorial'] ] model = Word2Vec(sentences, min_count=1) X = model[model.wv.vocab] pca = PCA(n_components=2) result = pca.fit_transform(X) pyplot.scatter(result[:, 0], result[:, 1]) words = list(model.wv.vocab) for i, word in enumerate(words): pyplot.annotate(word, xy=(result[i, 0], result[i, 1])) pyplot.show()
输出

Gensim - Doc2Vec 模型
Doc2Vec 模型与 Word2Vec 模型相反,用于创建一组单词的矢量化表示,这些单词被集体视为一个单元。它不仅仅给出句子中单词的简单平均值。
使用 Doc2Vec 创建文档向量
在这里使用 Doc2Vec 创建文档向量,我们将使用可以从 gensim.downloader 下载的 text8 数据集。
下载数据集
我们可以使用以下命令下载 text8 数据集 −
import gensim import gensim.downloader as api dataset = api.load("text8") data = [d for d in dataset]
下载 text8 数据集需要一些时间。
训练 Doc2Vec
为了训练模型,我们需要标记文档,可以使用以下方法创建models.doc2vec.TaggedDcument() 如下 −
def tagged_document(list_of_list_of_words): for i, list_of_words in enumerate(list_of_list_of_words): yield gensim.models.doc2vec.TaggedDocument(list_of_words, [i]) data_for_training = list(tagged_document(data))
我们可以按如下方式打印训练过的数据集 −
print(data_for_training [:1])
输出
[TaggedDocument(words=['anarchism', 'originated', 'as', 'a', 'term', 'of', 'abuse', 'first', 'used', 'against', 'early', 'working', 'class', 'radicals', 'including', 'the', 'diggers', 'of', 'the', 'english', 'revolution', 'and', 'the', 'sans', 'culottes', 'of', 'the', 'french', 'revolution', 'whilst', 'the', 'term', 'is', 'still', 'used', 'in', 'a', 'pejorative', 'way', 'to', 'describe', 'any', 'act', 'that', 'used', 'violent', 'means', 'to', 'destroy', 'the', 'organization', 'of', 'society', 'it', 'has', 'also', 'been' , 'taken', 'up', 'as', 'a', 'positive', 'label', 'by', 'self', 'defined', 'anarchists', 'the', 'word', 'anarchism', 'is', 'derived', 'from', 'the', 'greek', 'without', 'archons', 'ruler', 'chief', 'king', 'anarchism', 'as', 'a', 'political', 'philosophy', 'is', 'the', 'belief', 'that', 'rulers', 'are', 'unnecessary', 'and', 'should', 'be', 'abolished', 'although', 'there', 'are', 'differing', 'interpretations', 'of', 'what', 'this', 'means', 'anarchism', 'also', 'refers', 'to', 'related', 'social', 'movements', 'that', 'advocate', 'the', 'elimination', 'of', 'authoritarian', 'institutions', 'particularly', 'the', 'state', 'the', 'word', 'anarchy', 'as', 'most', 'anarchists', 'use', 'it', 'does', 'not', 'imply', 'chaos', 'nihilism', 'or', 'anomie', 'but', 'rather', 'a', 'harmonious', 'anti', 'authoritarian', 'society', 'in', 'place', 'of', 'what', 'are', 'regarded', 'as', 'authoritarian', 'political', 'structures', 'and', 'coercive', 'economic', 'institutions', 'anarchists', 'advocate', 'social', 'relations', 'based', 'upon', 'voluntary', 'association', 'of', 'autonomous', 'individuals', 'mutual', 'aid', 'and', 'self', 'governance', 'while', 'anarchism', 'is', 'most', 'easily', 'defined', 'by', 'what', 'it', 'is', 'against', 'anarchists', 'also', 'offer', 'positive', 'visions', 'of', 'what', 'they', 'believe', 'to', 'be', 'a', 'truly', 'free', 'society', 'however', 'ideas', 'about', 'how', 'an', 'anarchist', 'society', 'might', 'work', 'vary', 'considerably', 'especially', 'with', 'respect', 'to', 'economics', 'there', 'is', 'also', 'disagreement', 'about', 'how', 'a', 'free', 'society', 'might', 'be', 'brought', 'about', 'origins', 'and', 'predecessors', 'kropotkin', 'and', 'others', 'argue', 'that', 'before', 'recorded', 'history', 'human', 'society', 'was', 'organized', 'on', 'anarchist', 'principles', 'most', 'anthropologists', 'follow', 'kropotkin', 'and', 'engels', 'in', 'believing', 'that', 'hunter', 'gatherer', 'bands', 'were', 'egalitarian', 'and', 'lacked', 'division', 'of', 'labour', 'accumulated', 'wealth', 'or', 'decreed', 'law', 'and', 'had', 'equal', 'access', 'to', 'resources', 'william', 'godwin', 'anarchists', 'including', 'the', 'the', 'anarchy', 'organisation', 'and', 'rothbard', 'find', 'anarchist', 'attitudes', 'in', 'taoism', 'from', 'ancient', 'china', 'kropotkin', 'found', 'similar', 'ideas', 'in', 'stoic', 'zeno', 'of', 'citium', 'according', 'to', 'kropotkin', 'zeno', 'repudiated', 'the', 'omnipotence', 'of', 'the', 'state', 'its', 'intervention', 'and', 'regimentation', 'and', 'proclaimed', 'the', 'sovereignty', 'of', 'the', 'moral', 'law', 'of', 'the', 'individual', 'the', 'anabaptists', 'of', 'one', 'six', 'th', 'century', 'europe', 'are', 'sometimes', 'considered', 'to', 'be', 'religious', 'forerunners', 'of', 'modern', 'anarchism', 'bertrand', 'russell', 'in', 'his', 'history', 'of', 'western', 'philosophy', 'writes', 'that', 'the', 'anabaptists', 'repudiated', 'all', 'law', 'since', 'they', 'held', 'that', 'the', 'good', 'man', 'will', 'be', 'guided', 'at', 'every', 'moment', 'by', 'the', 'holy', 'spirit', 'from', 'this', 'premise', 'they', 'arrive', 'at', 'communism', 'the', 'diggers', 'or', 'true', 'levellers', 'were', 'an', 'early', 'communistic', 'movement', (truncated…)
初始化模型
训练完成后,我们现在需要初始化模型。可以按如下方式完成 −
model = gensim.models.doc2vec.Doc2Vec(vector_size=40, min_count=2, epochs=30)
现在,按如下方式构建词汇表 −
model.build_vocab(data_for_training)
现在,让我们按如下方式训练 Doc2Vec 模型 −
model.train(data_for_training, total_examples=model.corpus_count, epochs=model.epochs)
分析输出
最后,我们可以使用 model.infer_vector() 分析输出,如下所示 −
print(model.infer_vector(['violent', 'means', 'to', 'destroy', 'the','organization']))
完整实现示例
import gensim import gensim.downloader as api dataset = api.load("text8") data = [d for d in dataset] def tagged_document(list_of_list_of_words): for i, list_of_words in enumerate(list_of_list_of_words): yield gensim.models.doc2vec.TaggedDocument(list_of_words, [i]) data_for_training = list(tagged_document(data)) print(data_for_training[:1]) model = gensim.models.doc2vec.Doc2Vec(vector_size=40, min_count=2, epochs=30) model.build_vocab(data_training) model.train(data_training, total_examples=model.corpus_count, epochs=model.epochs) print(model.infer_vector(['violent', 'means', 'to', 'destroy', 'the','organization']))
输出
[ -0.2556166 0.4829361 0.17081228 0.10879577 0.12525807 0.10077011 -0.21383236 0.19294572 0.11864349 -0.03227958 -0.02207291 -0.7108424 0.07165232 0.24221905 -0.2924459 -0.03543589 0.21840079 -0.1274817 0.05455418 -0.28968817 -0.29146606 0.32885507 0.14689675 -0.06913587 -0.35173815 0.09340707 -0.3803535 -0.04030455 -0.10004586 0.22192696 0.2384828 -0.29779273 0.19236489 -0.25727913 0.09140676 0.01265439 0.08077634 -0.06902497 -0.07175519 -0.22583418 -0.21653089 0.00347822 -0.34096122 -0.06176808 0.22885063 -0.37295452 -0.08222228 -0.03148199 -0.06487323 0.11387568 ]