编者按:本文来自微信公众号"Social Listening与文本挖掘",CDA人工智能学院经授权发布。

本文会介绍几个在使用gensim进行文本挖掘所需了解的基本概念和术语,并提供一些简单的用法示例。

 

在更高层次上,gensim是一种通过检查词汇模式(或更高级别的结构,如语句或文档)来发现文档语义结构(Semantic Structure)的工具。 gensim通过语料库 --- 一组文本文档,并在语料库中生成文本的向量表示(Vector Representation of the Text)来实现这一点。 然后,文本的向量表示可用于训练模型 --- 它是用于创建不同的文本数据(蕴含语义)表示的算法。 这三个概念是理解gensim如何工作的关键,所以让我们花一点时间来解释它们的含义。 与此同时,我们将通过一个简单的例子来说明每个概念。

一 、语料(Corpus)

 

一个语料库是数字文档的集合(A Collection of Digital Documents)。 这个集合是gensim的输入,它将从中推断文档的结构或主题。从语料库中推断出的潜在结构(Latent Structure)可用于将主题分配给先前不存在于仅用于训练的语料库中的新文档。 出于这个原因,我们也将此集合称为训练语料库(Training Corpus)。 这个过程不需要人工干预(比如手动给文档打标签) --- 因为主题分类是无监督的(Unsupervised)(https://en.wikipedia.org/wiki/Unsupervised_learning)。

对于笔者用于示例的语料库,有12个文档,每个文档只有一个语句:

import jieba


jieba.add_word('知识图谱') #防止“知识图谱”被切错词


raw_corpus = ['商业新知:知识图谱为内核,构建商业创新服务完整生态。',
'如何更好利用知识图谱技术做反欺诈? 360金融首席数据科学家沈赟开讲。',
'知识管理 | 基于知识图谱的国际知识管理领域可视化分析。',
'一文详解达观数据知识图谱技术与应用。',
'知识图谱技术落地金融行业的关键四步。',
'一文读懂知识图谱的商业应用进程及技术背景。',
'海云数据CPO王斌:打造大数据可视分析与AI应用的高科技企业。',
'智能产业|《人工智能标准化白皮书2018》带来创新创业新技术标准。',
'国家语委重大科研项目“中华经典诗词知识图谱构建技术研究”开题。',
'最全知识图谱介绍:关键技术、开放数据集、应用案例汇总。',
'中译语通Jove Mind知识图谱平台 引领企业智能化发展。',
'知识图谱:知识图谱赋能企业数字化转型,为企业升级转型注入新能量。']


raw_corpus = [' '.join(jieba.lcut(i)) for i in raw_corpus]  #对语料库中的文档进行分词,便于后续处理
raw_corpus
['商业 新知 : 知识图谱 为 内核 , 构建 商业 创新 服务 完整 生态 。',
 '如何 更好 利用 知识图谱 技术 做 反 欺诈 ?   360 金融 首席 数据 科学家 沈赟开 讲 。',
 '知识 管理   |   基于 知识图谱 的 国际 知识 管理 领域 可视化 分析 。',
 '一文 详解 达观 数据 知识图谱 技术 与 应用 。',
 '知识图谱 技术 落地 金融 行业 的 关键 四步 。',
 '一文 读 懂 知识图谱 的 商业 应用 进程 及 技术 背景 。',
 '海云数 据 CPO 王斌 : 打造 大数据 可视 分析 与 AI 应用 的 高科技 企业 。',
 '智能 产业 | 《 人工 智能 标准化 白皮 书 2018 》 带来 创新 创业 新技术 标准 。',
 '国家 语委 重大 科研 项目 “ 中华经典 诗词 知识图谱 构建技术 研究 ” 开题 。',
 '最全 知识图谱 介绍 : 关键 技术 、 开放 数据集 、 应用 案例 汇总 。',
 '中译 语通 Jove   Mind 知识图谱 平台   引领 企业 智能化 发展 。',
 '知识图谱 : 知识图谱 赋能 企业 数字化 转型 , 为 企业 升级 转型 注入 新 能量 。']

这只是一个很小的语料库,其实你可以用其他的语料库进行替代,比如微信上的文章、微博博文,或者新闻标题等。

收集语料库之后,通常会进行一系列的文本预处理。 作为示例,为了简洁起见,笔者仅删除语料库中的停用词和在语料库中只出现一次的词汇。 在此过程中,笔者将进行分词操作,将文档分解为由词汇组成的列表(在本例中使用空格作为分隔符)。


# 移除常用词以及分词
stoplist = [i.strip() for i in open('datasets/stopwords_zh.txt',encoding='utf-8').readlines()]




#将文档中可能存在的西文字符小写化,按空格进行拆分,且去停用词
texts = [[word for word in document.lower().split() if word not in stoplist]
         for document in raw_corpus]


#计算词频
from collections import defaultdict
frequency = defaultdict(int)
for text in texts:
    for token in text:
        frequency[token] += 1


# 仅保留词频数高于1的词汇
processed_corpus = [[token for token in text if frequency[token] > 1] for text in texts]
processed_corpus
[['商业', '知识图谱', '商业', '创新'],
 ['知识图谱', '技术', '金融', '数据'],
 ['知识', '管理', '知识图谱', '知识', '管理', '分析'],
 ['一文', '数据', '知识图谱', '技术'],
 ['知识图谱', '技术', '金融', '关键'],
 ['一文', '知识图谱', '商业', '技术'],
 ['分析', '企业'],
 ['智能', '智能', '创新'],
 ['知识图谱'],
 ['知识图谱', '关键', '技术'],
 ['知识图谱', '企业'],
 ['知识图谱', '知识图谱', '企业', '转型', '企业', '转型']]

在继续之前,笔者希望将语料库中的每个词汇与唯一的整数ID相关联。 我们可以使用gensim.corpora.Dictionary这个类来完成。 这个词典定义了笔者之前预处理后的语料中的词汇。


from gensim import corpora

dictionary = corpora.Dictionary(processed_corpus)
print(dictionary)

Dictionary(14 unique tokens: ['创新', '商业', '知识图谱', '技术', '数据']...)

因为笔者给定的语料较小, 只有14个不同的词汇在这个 Dictionary中。 对于较大的语料库,词典中会包含成千上万的词汇,数量庞大。

二 、 向量空间(Vector Space)

为了推断语料库中的潜在结构(Latent Structure),我们需要一种可用于数学操作(比如,加减乘除等运算)的文档表示方法。一种方法是将每个文档表示为向量。有各种用于创建文档的向量表示的方法,其中一个简单的方法是词袋模型(Bag-of-Words Model)
在词袋模型下,每个文档由包含字典中每个单词的频率计数的向量表示。例如,给定一个包含词汇['咖啡','牛奶','糖果','勺子']的字典,那么,一个由字符串'咖啡 牛奶 糖果 勺子'组成的文档可以用向量表示为[2 ,1,0,0],其中向量的元素(按顺序)对应文档中出现的“咖啡”,“牛奶”,“糖”和“勺子”。向量的长度是字典中的词汇数。词袋模型的一个主要特性是它完全忽略了编码文档(the Encoded Document )中的词汇顺序,这就是词袋模型的由来。

我们处理过的语料库中有14个不同的词汇,这意味着语料库中的每个文档将由这个14维向量的词袋模型来表示。我们可以使用字典将分词后的文档转换为14维向量。由此,我们可以看到这些ID对应的词汇:


print(dictionary.token2id)

{'创新': 0, '商业': 1, '知识图谱': 2, '技术': 3, '数据': 4, '金融': 5, '分析': 6, '知识': 7, '管理': 8, '一文': 9, '关键': 10, '企业': 11, '智能': 12, '转型': 13}

例如,假设我们想要对“知识图谱为企业转型助力”这个语句进行向量化(请注意,该语句不在我们原来的语料库中)。 我们可以使用dictionary的doc2bow方法为该语句创建词袋表示,该方法返回词汇计数的稀疏表示:

new_doc = "知识图谱 为 企业 转型 助力"  #已分词,便于后续处理
new_vec = dictionary.doc2bow(new_doc.lower().split())
new_vec
[(2, 1), (11, 1), (13, 1)]

每个元组中的第一个元素对应字典中的词汇ID,第二个条目对应于该词汇的计数。

请注意,原始语料库中没有出现“为”、“助力”,因此它们将不包含于新生成的向量表示中。 另请注意,此向量仅包含实际出现在文档中的词汇。 因为任何给定文档只包含字典中许多单词中的几个单词,所以未参与向量化的词汇会直接被剔除,以节省空间。

我们可以将整个原始语料库转换为向量列表:


bow_corpus = [dictionary.doc2bow(text) for text in processed_corpus]
bow_corpus
[[(0, 1), (1, 2), (2, 1)],
 [(2, 1), (3, 1), (4, 1), (5, 1)],
 [(2, 1), (6, 1), (7, 2), (8, 2)],
 [(2, 1), (3, 1), (4, 1), (9, 1)],
 [(2, 1), (3, 1), (5, 1), (10, 1)],
 [(1, 1), (2, 1), (3, 1), (9, 1)],
 [(6, 1), (11, 1)],
 [(0, 1), (12, 2)],
 [(2, 1)],
 [(2, 1), (3, 1), (10, 1)],
 [(2, 1), (11, 1)],
 [(2, 2), (11, 2), (13, 2)]]

请注意,虽然此列表完全保存在内存中,但在大多数的应用场景,你需要更具伸缩性的解决方案(A More Scalable Solution)。幸运的是,gensim允许流式迭代器。 后面笔者会谈及。

三 、 模型(Model)

现在,我们已经对测试语料库进行了向量化,我们可以开始使用models对其进行转换了。 我们使用模型作为抽象术语,指的是从一个文档表示到另一个文档表示的转换。 在gensim中,文档表示为向量,因而模型可以被认为是两个向量空间之间的转换。 从训练语料库中学习这种转换的细节。

一个简单的模型示例是TF-IDF。 TF-IDF模型将向量从词袋表示(Bag-of-Words Representation)转换为向量空间,其中频率计数根据语料库中每个单词的相对稀有度(the relative rarity of each word in the corpus)进行加权。

这是一个简单的例子。 让我们初始化tf-idf模型,在测试语料库上进行训练,然后对字符串“知识图谱这种技术是企业转型的利器”进行转换:


from gensim import models
# 训练模型
tfidf = models.TfidfModel(bow_corpus)
# 对"知识图谱这种技术是企业转型的利器"进行转换
tfidf[dictionary.doc2bow("知识图谱 这种 技术 是 企业 转型 的 利器".split())]
[(2, 0.06112717038912965),
 (3, 0.29351946977430854),
 (11, 0.46478459877035777),
 (13, 0.8331176787522306)]

TF-IDF模型再次返回元组列表,每个元组的第一个元素是词汇ID,第二个条目是TF-IDF加权值。 注意,对应于“知识图谱”的ID(在训练语料库中出现10次)的加权值低于对应于“转型”的ID(在训练语料库中出现2次)权重值。

gensim提供了许多不同的模型/转换。