Python自然语言处理库 gensim核心概念

gensim 的核心概念包括:

  • Document:一些文本(text)。
  • Corpus:文档(documents)的集合。
  • Vector:文档(documents)的一种数学上方便的表示。
  • Model::一种将向量(Vector)从一种表示转换为另一种表示的算法。

Document

gensim 中,document 是文本序列类型的对象,文档可以是任何内容。

document = "Human machine interface for lab abc computer applications"

Corpus

corpusdocument 的集合。corpusgensim 中有两个角色:

  • 训练一个模型的输入。在训练过程中,模型使用 training corpus 寻找共同的主题,初始化内部模型参数。
  • 待组织的文档。训练完成后,可以使用主题模型从新文档(训练语料库中没有的文档)中提取主题。此类语料库可用于相似度查询索引、语义相似度查询、聚类等。

下面是一个示例语料库。它由9个文档组成,每个文档是由一个句子组成的字符串。

# 一次性载入全部语料
text_corpus = [
    "Human machine interface for lab abc computer applications",
    "A survey of user opinion of computer system response time",
    "The EPS user interface management system",
    "System and human system engineering testing of EPS",
    "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",
    "Graph minors A survey",
]
# 每次只载入一个文档Corpus Streaming

在收集到语料库之后,通常会有一些想要进行的预处理步骤。这里,只删除一些常用的英语单词(如’ the ')和只在语料库中出现过一次的单词。在此过程中,我们将标记我们的数据,标记化(Tokenization)将文档分解为单词(在本例中使用空格作为分隔符)。

# Create a set of frequent words
stoplist = set('for a of the and to in'.split(' '))
# Lowercase each document, split it by white space and filter out stopwords
texts = [[word for word in document.lower().split() if word not in stoplist]
         for document in text_corpus]

# Count word frequencies
from collections import defaultdict
frequency = defaultdict(int)
for text in texts:
    for token in text:
        frequency[token] += 1

# Only keep words that appear more than once
processed_corpus = [[token for token in text if frequency[token] > 1] for text in texts]
print(processed_corpus)
# Out
[['human', 'interface', 'computer'],
 ['survey', 'user', 'computer', 'system', 'response', 'time'],
 ['eps', 'user', 'interface', 'system'],
 ['system', 'human', 'system', 'eps'],
 ['user', 'response', 'time'],
 ['trees'],
 ['graph', 'trees'],
 ['graph', 'minors', 'trees'],
 ['graph', 'minors', 'survey']]

在继续之前,我们希望将语料库中的每个单词与一个惟一的整数ID关联起来,可以通过类gensim.corpora.Dictionary来实现。本词典定义了我们处理过程所知道的所有单词的词汇表。

from gensim import corpora
# 生成字典
dictionary = corpora.Dictionary(processed_corpus)
print(dictionary)
# Out
Dictionary(12 unique tokens: ['computer', 'human', 'interface', 'response', 'survey']...)

因为我们的语料库很小,所以在这个字典中只有12个不同的标记。对于较大的语料库,包含数十万标记的字典是很常见的。

Vector

为了推断语料库中的潜在结构,我们需要一种文档表示方法使得可以在数学上操作文档。

1. vector of features

一种方法是将每个文档表示为特征向量,一个特征可以被认为是一对问答:

  1. splonge这个单词在文档中出现多少次?零。
  2. 这个文件由多少个段落组成?两个。
  3. 文档使用多少字体?五个

问题通常只用它的整数id(比如1、2和3)表示,然后文档的表示就变成元组对的集合:

  • dense vector:包含所有的问题及它的答案。例如(1, 0.0), (2, 2.0), (3, 5.0)。
  • sparse vector / bag-of-words vector:忽略答案值为0的元组对。例如(2, 2.0), (3, 5.0)。

假设问题是相同的,我们可以比较两个不同文档的向量。例如,假设我们有两个向量(0.0,2.0,5.0)和(0.1,1.9,4.9)。因为这些向量彼此非常相似,所以我们可以得出结论,这些向量对应的文档也是相似的。当然,这个结论的正确性取决于我们一开始选择问题的好坏。

2. bag-of-words models

另一种将文档表示成向量的方法是 bag-of-words 模型(词袋模型)。在词袋模型中,每个文档由一个向量表示,这个向量包含字典中每个单词的频率计数。例如,假设我们有一个字典包含单词 [‘coffee’, ‘milk’, ‘sugar’, ‘spoon’],一个包含字符串 “coffee milk coffee” 的文档可以表示为向量[2, 1, 0, 0],其中向量的第1、2、3、4项分别表示单词 ‘coffee’, ‘milk’, ‘sugar’, ‘spoon’ 在文档中出现的次数,向量的长度是字典中的单词数。词袋模型的一个主要特点是它完全忽略了文档中单词出现的顺序。

我们处理过的语料库中有12个不同的单词,这意味着每个文档将在词袋模型下将会由一个12维向量表示。我们可以使用 dictionary 将标记过的文档转换成12维向量。可以看到这些 id 对应的是:

# diction.token2id 存放的是{单词-id}key-value对
print(dictionary.token2id)
# out
{'computer': 0,
 'eps': 8,
 'graph': 10,
 'human': 1,
 'interface': 2,
 'minors': 11,
 'response': 3,
 'survey': 4,
 'system': 5,
 'time': 6,
 'trees': 9,
 'user': 7}

例如,假设我们希望向量化短语 “Human computer interaction” (注意,这个短语不在我们最初的语料库中)。我们可以使用 dictionary 的 doc2bow 方法为文档创建词袋表示,该方法返回单词计数的稀疏表示:

new_doc = "Human computer interaction"
new_vec = dictionary.doc2bow(new_doc.lower().split())
print(new_vec)
[(0, 1), (1, 1)]

每个元组中的第一个项对应于字典中单词的ID,第二个项对应于该单词的频数。
请注意,单词 “interaction” 在原始语料库中没有出现,因此不包括在向量中。还要注意,这个向量只包含实际出现在文档中的单词。由于任何给定的文档只包含字典中众多单词中的少数几个单词,因此没有在向量中出现的单词被隐式地表示为零,以节省空间。

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

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

Model

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

tf-idf

tf-idf 模型将文档的词袋表示转换为另一种向量表示,新的向量空间中,根据语料库中每个词的相对罕见度对频数进行加权。
t f − i d f ( w , d , c ) = t f ( w , d ) × i d f ( w , c ) = 词 w 在 文 档 d 中 出 现 次 数 文 档 d 中 单 词 总 数 ( 含 重 复 ) × log ⁡ ( 语 料 库 c 中 文 档 总 数 包 含 词 w 的 文 档 数 + 1 ) tf-idf(w,d,c)=tf(w,d)\times idf(w,c) = \frac{词w在文档d中出现次数}{文档d中单词总数(含重复)}\times \log(\frac{语料库c中文档总数}{包含词w的文档数+1}) tfidf(w,d,c)=tf(w,d)×idf(w,c)=dwd×log(w+1c)

举一个简单的例子,初始化 tf-idf 模型,在我们的语料库上训练它,并转换字符串“system minor”:

from gensim import models
# train the model
tfidf = models.TfidfModel(bow_corpus)
# transform the "system minors" string
words = "system minors".lower().split()
print(tfidf[dictionary.doc2bow(words)])
# out
[(5, 0.5898341626740045), (11, 0.8075244024440723)]

tfidf 模型返回一个元组列表,其中元组的第一个项是字符ID,第二个项是 tf-idf 权重值。

一旦创建了模型,你就可以用它做各种很酷的事情。例如,通过TfIdf对整个语料库进行转换并建立索引,为相似度查询做准备:

from gensim import similarities
index = similarities.SparseMatrixSimilarity(tfidf[bow_corpus], num_features=12)

查询我们的查询文档query_document与语料库中每个文档的相似性:

query_document = 'system engineering'.split()
query_bow = dictionary.doc2bow(query_document)
sims = index[tfidf[query_bow]]
print(list(enumerate(sims)))
# out
[(0, 0.0), (1, 0.32448703), (2, 0.41707572), (3, 0.7184812), (4, 0.0), (5, 0.0), (6, 0.0), (7, 0.0), (8, 0.0)]

为了增强可读性:

for document_number, score in sorted(enumerate(sims), key=lambda x: x[1], reverse=True):
    print(document_number, score)
# out
3 0.7184812
2 0.41707572
1 0.32448703
0 0.0
4 0.0
5 0.0
6 0.0
7 0.0
8 0.0

Core Tutorials: New Users Start Here!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值