目录
一、原理介绍
Word2Vec有两种主要的模型架构:连续词袋模型(Continuous Bag of Words,简称CBOW)和跳字模型(Skip-gram)。训练Word2Vec的核心目标是通过调整单词向量的权重,使得模型能够最小化实际上下文单词的预测误差。通过多次迭代,模型将学习到单词向量,这些向量在向量空间中能够捕获单词之间的语义关系,使得具有相似语义的单词在向量空间中距离较近。
1、CBOW
在CBOW模型中,给定上下文单词,目标是预测中心单词。例如,对于句子 "Thou shalt not make a machine in the likeness of a human mind",如果我们将上下文大小设置为1,那么对于中心单词 "machine",上下文单词可以是 ["a", "in"]。
结合上图,CBOW训练过程如下:
① 输入层(Input layer):目标单词上下文的单词,每个单词用ont-hot编码表示,为[1 * V]大小的矩阵,V表示词汇大小;
② 所有的ont-hot矩阵乘以输入权重矩阵W,W是[V * N]大小的共享矩阵,N是指输出的词的向量维数;
③ 将相乘得到的向量 ([1 * V] 的ont-hot矩阵乘上[V * N]的共享矩阵W) 相加,然后求平均作为隐层向量h, 大小为[1 * N];
④ 将隐层向量h乘以输出权重矩阵W',W'是[N * V]大小的共享矩阵;
⑤ 相乘得到向量y,大小为[1 * V],然后利用softmax激活函数处理向量y,得到V-dim概率分布;
⑥ 由于输入的是ont-hot编码,即每个维度都代表着一个单词,那么V-dim概率分布中,概率最大的index所指代的那个单词为预测出的中间词。
⑦ 将结果与真实标签的ont-hot做比较,误差越小越好,这里的误差函数,即loss function一般选交叉熵代价函数。
以上为CBOW生成词向量的全过程。如果我们只是想提取每个单词的向量,那么只需要得到向量y就可以了,但训练过程中要去做预测并计算误差,去求得输入权重矩阵W和输出权重矩阵W'。
2、Skip-gram
在Skip-gram模型中,目标是给定中心单词,预测其周围的上下文单词。
如上图所示,Skip-gram和CBOW模型的训练区别主要在输入层和隐层,Skip-gram输入层仅中心词的one-hot向量、隐藏层也就不需要再进行平均操作。
过程如下:
① 输入层(Input layer):将中心单词用ont-hot编码表示,为[1 * V]大小的矩阵
② 中心词ont-hot向量乘以输入权重矩阵W得到大小为[1 * N]的隐藏层向量h,W是[V * N]大小的共享矩阵,N是指输出的词的向量维数;
之后就和CBOW一致了
③ 将隐层向量h乘以输出权重矩阵W',W'是[N * V]大小的共享矩阵;
④相乘得到向量y,大小为[1 * V],然后利用softmax激活函数处理向量y,得到V-dim概率分布;
⑤由于输入的是ont-hot编码,即每个维度都代表着一个单词,那么V-dim概率分布中,概率最大的index所指代的那个单词为预测出的上下文单词。
⑥ 将结果与真实标签的ont-hot做比较,误差越小越好,这里的误差函数,即loss function一般选交叉熵代价函数。
3、目的
word2vec的目的并不在于预测上下文的语言模型,而是在于训练得到中间结果输入层到隐藏层之间的权重矩阵W、即Embedding矩阵,即词向量矩阵。把每个词使用向量形式表示之后,在文本任务中就可以继续进行文本分类、文本相似度、推荐等等下游任务。
二、参数详解及实战
1、导包
import re
import os
from sqlalchemy import create_engine
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
import sklearn
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve,roc_auc_score
import xgboost as xgb
from xgboost.sklearn import XGBClassifier
import lightgbm as lgb
import matplotlib.pyplot as plt
import gc
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras import models
from tensorflow.keras import layers
from tensorflow.keras import optimizers
2、数据读取+预处理
data=pd.read_excel('Inshorts Cleaned Data.xlsx')
def data_preprocess(data):
df=data.drop(['Publish Date','Time ','Headline'],axis=1).copy()
df.rename(columns={'Source ':'Source'},inplace=True)
df=df[df.Source.isin(['YouTube','India Today'])].reset_index(drop=True)
df['y']=np.where(df.Source=='YouTube',1,0)
df=df.drop(['Source'],axis=1)
return df
df=data.pipe(data_preprocess)
print(df.shape)
df.head()
3、导入英文停用词
从nltk包倒入停用词
from nltk.corpus import stopwords
from nltk.tokenize import sent_tokenize
stop_english=stopwords.words('english')
stop_spanish=stopwords.words('spanish')
stop_english
4、文本预处理
处理简写、小写化、去除停用词、词性还原
from nltk.stem import WordNetLemmatizer
from nltk.corpus import stopwords
from nltk.tokenize import sent_tokenize
import nltk
def replace_abbreviation(text):
rep_list=[
("it's", "it is"),
("i'm", "i am"),
("he's", "he is"),
("she's", "she is"),
("we're", "we are"),
("they're", "they are"),
("you're", "you are"),
("that's", "that is"),
("this's", "this is"),
("can't", "can not"),
("don't", "do not"),
("doesn't", "does not"),
("we've", "we have"),
("i've", " i have"),
("isn't", "is not"),
("won't", "will not"),
("hasn't", "has not"),
("wasn't", "was not"),
("weren't", "were not"),
("let's", "let us"),
("didn't", "did not"),
("hadn't", "had not"),
("waht's", "what is"),
("couldn't", "could not"),
("you'll", "you will"),
("i'll", "i will"),
("you've", "you have")
]
result = text.lower()
for word_replace in rep_list:
result=result.replace(word_replace[0],word_replace[1])
# result = result.replace("'s", "")
return result
def drop_char(text):
result=text.lower()
result=re.sub('[^\w\s]',' ',result) # 去掉标点符号、特殊字符
result=re.sub('\s+',' ',result) # 多空格处理为单空格
return result
def stemed_words(text,stop_words,lemma):
word_list = [lemma.lemmatize(word, pos='v') for word in text.split() if word not in stop_words]
result=" ".join(word_list)
return result
def text_preprocess(text_seq):
stop_words = stopwords.words("english")
lemma = WordNetLemmatizer()
result=[]
for text in text_seq:
if pd.isnull(text):
result.append(None)
continue
text=replace_abbreviation(text)
text=drop_char(text)
text=stemed_words(text,stop_words,lemma)
result.append(text)
return result
df['short']=text_preprocess(df.Short)
df[['Short','short']]
5、划分训练、测试集
test_index=list(df.sample(2000).index)
df['label']=np.where(df.index.isin(test_index),'test','train')
df['label'].value_counts()
6、word2vec参数详解及训练
import gensim
def word2vec_train(sentences):
# 训练词向量矩阵用于embedding权重时,max_vocab_size设置为None
'''
sentences为分词、去停用词、去符号回车等的结果、单层列表
如:["only", "you", "can", "prevent", "forest", "fires"]
'''
params={
'sg':1, # 1对应skip-gram,0对应CBOW
'cbow_mean':1, # CBOW时使用,1计算向量均值、0计算向量和
'min_count':1, # 最低词频阈值,低于min_count的词过滤掉
'vector_size':128, # 词向量维度,取值几十到几百
'window':5, # 滑动窗口,当前词与上下文词最远距离
'workers':1, # 计算使用线程数
'hs':1, # 设置1,将使用分层softmax进行模型训练;设置0且“negative”为非零,则将使用负采样
'negative':3, # 负样本采样数量
'seed':1,
'max_vocab_size':None, # 词典最大词汇量
'shrink_windows':False, # 设置True时,对每个目标词,从[1,windows]范围进行均匀采样、以确定每个词的实际窗口大小
'ns_exponent':1,
'sample':0.001, # 高频字随机降采样的阈值
'epochs':5, # 语料上的迭代次数
'alpha':0.025, # learning rate
'corpus_file':None, # 指定sentences文档路径,与sentences仅传一个就好
}
model = gensim.models.word2vec.Word2Vec(sentences=sentences, **params)
return model
word2vec_model=word2vec_train(list(df.short.str.split()))
vec_king = word2vec_model.wv['king']
vec_king
三、划重点
少走10年弯路
关注威信公众号Python风控模型与数据分析,回复 word2vec 获取本篇数据及代码
还有更多理论、代码分享等你来拿