自然语言处理——使用词向量(腾讯词向量)

#自然语言处理

向量化是使用一套统一的标准打分,比如填写表格:年龄、性别、性格、学历、经验、资产列表,并逐项打分,分数范围 [-1,1],用一套分值代表一个人,就叫作向量化,虽然不能代表全部,但至少是个量度。因此,可以说,万物皆可向量化。

词向量

同理,词也可以向量化 word2vec(word to vector),可以从词性、感情色彩、程度等等方面量度,用一套分值代表一个词,从而词之间可以替换,比较。词与向量间的转换过程就叫作词的向量化。与人为评分不同的是,词向量一般通过训练生成,其每一维量度的作用也并不明确。词向量化常用于提取词的特征,提取后的特征再代入模型计算。

词向量如下图所示:

上图把每个单词映射到 50 个维度(用 50 种特征表示一个词),每个维度在 [-1,1] 范围内取值,上图中 1 为红色,0 为白色,-1 为蓝色,中间各值为过渡色,从图中可以直观看到词间的相似度。获取了词向量之后,除了可以计算词间或句间相似度,查找近义词,代入模型以外,还可以做组合词义,以及排除某种含义,如下图所示:

https://jalammar.github.io/illustrated-word2vec/

Gensim

Gensim 是一款常用的自然语言处理工具,提供 Python 三方工具包,常用于从文本中提取特征,提供 TF-IDF,LSA,LDA,word2vec 等功能。开发者可以用它训练自己的词向量,也可以使用他人训练好的词向量。

使用 Gensim 支持用数据训练词向量,网上例程很多。其原理是一种无监督学习,通过代入大量文章,根据各个词与其上下文关系,挖掘词义。一般自然语言处理的深度学习模型的第一层都是词向量化,因此,除了使用 Gensim 训练,还可以从其它模型中导出词向量。需要注意的是:高相似度表示两个词通常可以互换。并不一定是同义词,很多情况下,替换成反意词后句子也能读通,但含义完全不同。

腾讯词向量

腾讯词向量提供 800 多万中文词条,每个词条展开成 200 维向量,解压后 16G。它使用 Directional Skip-Gram(Skip-Gram 的改进版)训练而成,可使用 Ginsim 调用。相对于传统的同义词词林和词表,可以说非常先进了。它提供的是通常意义上的词义,但对于具体任务不是很完美。可从以下网址下载腾讯词向量:https://ai.tencent.com/ailab/nlp/embedding.html 下面是官方示例。

那么何时选择腾讯词向量,何时又需要自己训练模型计算词向量?二者各有利弊,腾讯词向量体量大,速度慢,但涵盖的词和短语非常丰富,准确率也比较高。如果使用模型训练,则可针对某一目标训练,比如判别感情色彩时,某个词的表征和通常情况下的表征很可能有所不同,模型训练需要有足够的训练集,还要考虑模型支持词表(以字为单位还是以词为单位,如何分词),向量维度等等问题,难度更大,选择应视情况而定。

示例:

找近义词

1
2
3
4
5
6
7
8
9
10
from gensim.models import KeyedVectors
file = '/exports/nlp/Tencent_AILab_ChineseEmbedding.txt'
wv_from_text = KeyedVectors.load_word2vec_format(file, binary=False) # 加载时间比较长
wv_from_text.init_sims(replace=True)
word = '膝关节置换手术'
if word in wv_from_text.wv.vocab.keys():
vec = wv_from_text[word]
print(wv_from_text.most_similar(positive=[vec], topn=20))
else:
print("没找到")

其运行结果如下图所示,看似比较合理。

有一些专有名词或者短语,可能没收录在词库中,这种情况下可以使用先拆词,对其中各个词分别映射向量,然后取均值的方法计算。

计算词距

这里指的距离,并不是近义词或者反义词,只是句中该处是否可被另一个词替换的可能性。

1
2
3
print(wv_from_text.distance("喜欢", "讨厌")) # 0.299, 数越小越近
print(wv_from_text.distance("喜欢", "爱")) # 0.295
print(wv_from_text.distance("喜欢", "西瓜")) # 0.670

计算字串距离

通过余弦距离计算距离 数学方法,结果为 1 时为正相关,为 0 时不相关,为 -1 时负相关。

1
2
print(wv_from_text.n_similarity(['风景', '怡人'],['山美','水美'])) # 0.60
print(wv_from_text.n_similarity(['风景', '怡人'],['上','厕所'])) # 0.43