Keras深度學習——使用skip-gram和CBOW模型構建單詞向量

語言: CN / TW / HK

本站內容均來自興趣收集,如不慎侵害的您的相關權益,請留言告知,我們將盡快刪除.謝謝.

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第29天,點選檢視活動詳情

skip-gram 和 CBOW 模型

本節中,使用連續單詞袋 ( Continuous Bag of Words , CBOW ) 模型構建單詞向量,以 “ I love watching movie ” 為例。 CBOW 模型處理此語句的方式如下:

輸入單詞 輸出單詞
{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上獲取格式化資料集。可以看到,資料集中包含每條推文對六家美國航空公司的評價情緒是正面的、中性的還是負面的:

接下來,我們利用 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)