持续创造,加速成长!这是我参与「日新方案 6 月更文挑战」的第29天,点击检查活动详情

skip-gram 和 CBOW 模型

本节中,运用接连单词袋 (Continuous Bag of Words, CBOW) 模型构建单词向量,以 “I love watching movie” 为例。CBOW 模型处理此语句的方式如下:

  • 运用一个尺度为 1 的特定窗口
  • 经过指定窗口巨细,也表明指定了在给定单词的右侧和左边将考虑的单词数
  • 给定窗口巨细 1,则输入和输出单词如下所示:
输入单词 输出单词
{I, watching} {love}
{love, movie} {watching}
  • 构建单词向量的另一种办法是运用 skip-gram 模型,其过程与 CBOW 过程恰好相反,如下所示:
输出单词 输入单词
{love} {I, watching}
{watching} {love, movie}

但无论是 skip-gram 模型仍是 CBOW 模型,得到单词在隐藏层的编码向量的办法都与在 <测量词向量之间的类似度>中介绍的办法相同。

运用 skip-gram 和 CBOW 模型构建单词向量

了解了单词向量构建的原理后,咱们运用 skip-gramCBOW 模型构建单词向量。为了构建模型,咱们将运用航空公司的情感数据集,其间给出了推文文本,并提供了与推文相对应的情感。

咱们所用的 Twitter US Airline Sentiment 数据来源于 Crowdflower’s Data for Everyone,其间包括了美国各大航空公司 Twitter 评论的情绪分析数据,该数据集收集了自 20152 月以来的数据,并推文进行分类,包括正面、负面和中立,数据集还对负面点评原因的进行分类,例如“航班迟到”或“服务粗鲁”等。能够在 Kaggle 上获取格式化数据集。能够看到,数据集中包括每条推文对六家美国航空公司的点评情绪是正面的、中性的仍是负面的:

Keras深度学习——使用skip-gram和CBOW模型构建单词向量

接下来,咱们运用 gensim 库生成单词向量。如果未装置此库,首先运用 pip 指令进行装置:

pip install gensim

导入相关库,并读取航空公司 Twitter 情感数据集,其间包括与航空公司及其相应情感相关的评论内容:

import gensim
import pandas as pd
data = pd.read_csv('archive/Tweets.csv')
print(data.head())

预览数据集,如下所示:

             tweet_id airline_sentiment  ...  tweet_location               user_timezone
0  570306133677760513           neutral  ...             NaN  Eastern Time (US & Canada)
1  570301130888122368          positive  ...             NaN  Pacific Time (US & Canada)
2  570301083672813571           neutral  ...       Lets Play  Central Time (US & Canada)
3  570301031407624196          negative  ...             NaN  Pacific Time (US & Canada)
4  570300817074462722          negative  ...             NaN  Pacific Time (US & Canada)

对读取的文本进行预处理,执行以下操作:

  • 将每个单词都转换为小写
  • 删去标点符号,仅保留数字和字母
  • 删去停用词
import re
import nltk
from nltk.corpus import stopwords
stop = set(stopwords.words('english'))
def preprocess(text):
    text = text.lower()
    text = re.sub('[^0-9a-zA-Z]+', ' ', text)
    words = text.split()
    words2 = [i for i in words if i not in stop]
    words3 = ' '.join(words2)
    return words3
data ['text'] = data['text'].apply(preprocess)

将语句拆分为分词 (token) 列表,以便随后将其传递给 gensim,打印出第一句的分词成果:

print(data['text'][0].split())

以上代码将语句按空格分隔,输出如下所示:

['virginamerica', 'dhepburn', 'said']

遍历一切文本,并将分词成果添加到列表中,如下所示:

list_words = []
for i in range(len(data)):
    list_words.append(data['text'][i].split())

检查 list_words 列表中的前 5 个分词成果:

print(list_words[:5])

前三个语句的列表如下:

[['virginamerica', 'dhepburn', 'said'], ['virginamerica', 'plus', 'added', 'commercials', 'experience', 'tacky'], ['virginamerica', 'today', 'must', 'mean', 'need', 'take', 'another', 'trip'], ['virginamerica', 'really', 'aggressive', 'blast', 'obnoxious', 'entertainment', 'guests', 'faces', 'amp', 'little', 'recourse'], ['virginamerica', 'really', 'big', 'bad', 'thing']]

接下来,构建 Word2Vec 模型,定义单词向量巨细、要检查的上下文窗口巨细,以及要考虑单词的最小数量,以使其具有被编码为向量的资历,如下所示:

from gensim.models import Word2Vec
model = Word2Vec(vector_size=50, window=5, min_count=30, sg=0, alpha=0.025)

在以上代码中,vector_size 表明单词向量的维度,window 表明要考虑的单词的上下文巨细,min_count 指定要考虑的单词的最小频率,sg 表明选用的编码模型为运用 skip-gram (sg = 1) 或CBOW (sg = 0),alpha 表明模型的学习率。

定义模型后,传递 list_words 列表以构建词汇表,如下所示:

model.build_vocab(list_words)

构建词汇表后,能够找到在整个语料库中过滤掉少于 30 次的单词后剩下的最终单词,如下所示:

print(model.wv.index_to_key)

输出成果如下所示:

['united', 'flight', 'usairways', 'americanair', 'southwestair', 'jetblue', 'get', 'co', 'http', 'thanks', 'cancelled', 'service'...]

经过指定输入数据和要练习的 epoch 数来练习模型,如下所示:

model.train(list_words, total_examples=model.corpus_count, epochs=200)

train 办法中,list_words 列表包括了一切输入分词列表,total_examples 表明要考虑的分词列表总数,epochs 是要运行的 epoch 数。

此外,咱们也能够经过在 Word2Vec 办法中运用 iter 参数来指定练习模型 epoch 数,如下所示:

model.train(list_words, total_examples=model.corpus_count, iter=200)

练习完成后,能够提取给定单词的单词编码向量,如下所示:

print(model.wv.get_vector('day'))

对应于单词 “day” 的单词向量如下:

[-7.04173684e-01 -5.72516641e-04 -4.10758048e-01  1.84985828e+00
 -1.15435565e+00 -3.16574931e-01 -5.16422510e-01  2.28969193e+00
  1.91934001e+00 -1.18813097e+00 -2.94377494e+00  9.51616392e-02
 -8.44838619e-02 -7.18616024e-02 -1.14567673e+00  6.77643716e-01
  1.61244774e+00  1.13801873e+00 -4.42255348e-01  1.07233655e+00
  1.16125333e+00  2.79197335e+00  2.07479763e+00 -1.21500826e+00
 -9.10723388e-01  4.01439548e-01 -1.65728176e+00 -1.75016761e-01
 -9.88252282e-01 -3.28201318e+00 -1.22636998e+00 -6.90755486e-01
 -1.92077053e+00  1.75805852e-01 -2.02697372e+00 -9.76259783e-02
  1.68322384e+00 -1.77150667e+00  3.45278442e-01 -2.07601279e-01
 -1.24472260e+00  7.59482205e-01  7.28200555e-01 -2.57247114e+00
 -1.04648125e+00  2.81359744e+00 -2.41322589e+00 -1.54843581e+00
  2.38953400e+00 -1.05442435e-01]

两个词之间的类似度能够运用 similarity 计算如下:

print(model.wv.similarity('day', 'week'))
# 输出成果
# 0.53549874

同样,咱们能够计算与给定单词最类似的单词,以及它们之间的类似度:

print(model.wv.most_similar('day'))

与单词 “day” 最类似的单词打印如下:

[('days', 0.6186136603355408), ('week', 0.5354987382888794), ('trip', 0.5184321999549866), ('time', 0.4801279306411743), ('destination', 0.4254339635372162), ('hrs', 0.4112888276576996), ('night', 0.41115307807922363), ('hours', 0.40979164838790894), ('year', 0.3568463921546936), ('sat', 0.3532494604587555)]

尽管这些类似度看起来很低,并且一些类似的单词并没有被精确的识别,这是由于该数据库中的数据量并不足以得到更精确的成果,能够在一个更大的数据集上进行练习。

经过将 sg 参数的值替换为 1,则能够运用 skip-gram 模型取得单词低维向量:

model = Word2Vec(vector_size=50, window=5, min_count=30, sg=1)