NLP-⽂本向量化:WordEmbedding⼀般步骤【字符串->分词->词汇序列化->
词。。。
⼀、字符串⽂本的序列化
在word embedding的时候,不会直接把⽂本转化为向量,⽽是先转化为数字,再把数字转化为向量,那么这个过程该如何实现呢?
这⾥我们可以考虑把⽂本中的每个词语和其对应的数字,使⽤字典保存,同时实现⽅法把句⼦通过字典映射为包含数字的列表。
实现⽂本序列化之前,考虑以下⼏点:
1. 如何使⽤字典把词语和数字进⾏对应
2. 不同的词语出现的次数不尽相同,是否需要对⾼频或者低频词语进⾏过滤,以及总的词语数量是否需要进⾏限制
江疏影2分28秒3. 得到词典之后,如何把句⼦转化为数字序列,如何把数字序列转化为句⼦
4. 不同句⼦长度不相同,每个batch的句⼦如何构造成相同的长度(可以对短句⼦进⾏填充,填充特殊字符)
5. 对于新出现的词语在词典中没有出现怎么办(可以使⽤特殊字符代理)
思路分析:
1. 对所有句⼦进⾏分词
2. 词语存⼊字典,根据次数对词语进⾏过滤,并统计次数
3. 实现⽂本转数字序列的⽅法
4. 实现数字序列转⽂本⽅法
如何养殖富贵竹⽂本序列化功能类WordSequence的构建
import numpy as np
import pickle
# =======================================⽂本序列化:开始=======================================
电费网上缴费
class WordSequence:
UNK_TAG ="<UNK>"# 表⽰未在词典库⾥出现的未知词汇
PAD_TAG ="<PAD>"# 句⼦长度不够时的填充符
SOS_TAG ="<SOS>"# 表⽰⼀句⽂本的开始
EOS_TAG ="<EOS>"# 表⽰⼀句⽂本的结束
UNK =0
PAD =1
SOS =2
EOS =3
def__init__(self):
self.word_index_dict ={
self.UNK_TAG: self.UNK,
self.PAD_TAG: self.PAD,
self.SOS_TAG: self.SOS,
self.EOS_TAG: self.EOS}# 初始化词语-数字映射字典
self.index_word_dict ={}# 初始化数字-词语映射字典
self.word_count_dict ={}# 初始化词语-词频统计字典
管理技能
self.fited =False
def__len__(self):
return len(self.word_index_dict)
# 接受句⼦,统计词频得到
def fit(self,sentence,min_count=1,max_count=None,max_features=None):# 【min_count:最⼩词频; max_count: 最⼤词频; max_features: 最⼤词语数(词典容量⼤⼩)】
词典容量⼤⼩)】
"""
:param sentence:[word1,word2,word3]
:param min_count: 最⼩出现的次数
:param max_count: 最⼤出现的次数
:param max_feature: 总词语的最⼤数量
:return:
"""
for word in sentence:
self.word_count_dict[word]= self.word_(word,0)+1#所有的句⼦fit之后,self.word_count_dict就有了所有词语的词频if min_count is not None:# 根据条件统计词频
self.word_count_dict ={word:count for word,count in self.word_count_dict.items()if count >= min_count}
if max_count is not None:#  根据条件统计词频
self.word_count_dict ={word:count for word,count in self.word_count_dict.items()if count <= max_count}# 根据条件构造词典if max_features is not None:# 根据条件保留⾼词频词语
self.word_count_dict =dict(sorted(self.word_count_dict.items(),key=lambda x:x[-1],reverse=True)[:max_features])# 保留词频排名靠前的词汇【se lf.word_count_dict.items()为待排序的对象,key表⽰排序指标,reverse=True表⽰降序排列】
for word in self.word_count_dict:# 根据word_count_dict字典构造词语-数字映射字典
if word not in self.word_index_dict.keys():# 如果当前词语word还没有添加到word_index_dict字典,则添加
self.word_index_dict[word]=len(self.word_index_dict)# 每次word对应⼀个数字【使⽤self.word_index_dict添加当前word前已有词汇的数量作为其value】
self.fited =True
self.index_word_dict =dict(zip(self.word_index_dict.values(),self.word_index_dict.keys()))#把word_index_dict进⾏翻转【准备⼀个index->word的字典】
# word -> index
def to_index(self,word):
assert self.fited ==True,"必须先进⾏fit操作"
return self.word_(word,self.UNK)
# 把句⼦转化为数字数组(向量)【输⼊:[str,str,str];输出:[int,int,int]】
def transform(self,sentence,max_len=None,add_eos=False):
if len(sentence)> max_len:# 句⼦过长,截取句⼦
if add_eos:# 如果每句⽂本需要添加<EOS>结束标记
sentence = sentence[:max_len-1]+[self.EOS]
else:
sentence = sentence[:max_len]
else:# 句⼦过短,填充句⼦
if add_eos:# 如果每句⽂本需要添加<EOS>结束标记
sentence = sentence +[self.EOS]+[self.PAD_TAG]*(max_len -len(sentence)-1)
else:
sentence = sentence +[self.PAD_TAG]*(max_len -len(sentence))
index_sequence =[_index(word)for word in sentence]
return index_sequence
# index -> word
def to_word(self,index):
assert self.fited ,"必须先进⾏fit操作"
if index in self.inversed_dict:
return self.inversed_dict[index]
return self.UNK_TAG
# 把数字数组(向量)转化为句⼦【输⼊:[int,int,int];输出:[str,str,str]】
def inverse_transform(self,indexes):
sentence =[self.index_(index,"<UNK>")for index in indexes]
return sentence
# =======================================⽂本序列化:结束=======================================
if __name__ =='__main__':
sentences =[["今天","天⽓","很","好"],["今天","去","吃","什么"]]
ws = WordSequence()
for sentence in sentences:
ws.fit(sentence)
print("ws.word_index_dict = {0}".format(ws.word_index_dict))
print("ws.fited = {0}".format(ws.fited))
pickle.dump(ws,open("./models/ws.pkl","wb"))# 保存⽂本序列化对象
pickle.dump(ws,open("./models/ws.pkl","wb"))# 保存⽂本序列化对象
ws = pickle.load(open("./models/ws.pkl","rb"))# 加载⽂本序列化对象
index_sequence = ws.transform(["今天","很","热"],max_len=10)
print("index_sequence = {0}".format(index_sequence))
输出结果:
ws.word_index_dict ={'<UNK>':1,'<PAD>':0,'今天':2,'天⽓':3,'很':4,'好':5,'去':6,'吃':7,'什么':8}
ws.fited =True
index_sequence =[2,4,1,0,0,0,0,0,0,0]
⼆、“序列化后的字符串⽂本” 进⾏向量化
因为⽂本不能够直接被模型计算,所以需要将其转化为向量。
将⼀段⽂本使⽤张量进⾏表⽰,其中⼀般将词汇为表⽰成向量,称作词向量,再由各个词向量按顺序组成矩阵形成⽂本表⽰.
举个栗⼦:
["⼈⽣", "该", "如何", "起头"]
==>
# 每个词对应矩阵中的⼀个向量
[[1.32, 4,32, 0,32, 5.2],
[3.1, 5.43, 0.34, 3.2],
[3.21, 5.32, 2, 4.32],
[2.54, 7.32, 5.12, 9.54]]
⽂本张量表⽰的作⽤:将⽂本表⽰成张量(矩阵)形式,能够使语⾔⽂本可以作为计算机处理程序的输⼊,进⾏接下来⼀系列的解析⼯作。
⽂本张量表⽰的⽅法:
one-hot编码
Word Embedding
1、one-hot编码
在one-hot编码中,每⼀个token使⽤⼀个长度为N的向量表⽰,N表⽰词典的数量。
one-hot编码⼜称独热编码,将每个词表⽰成具有n个元素的向量,这个词向量中只有⼀个元素是1,其他元素都是0,不同词汇元素为0的位置不同,其中n的⼤⼩是整个语料中不同词汇的总数.
即:把待处理的⽂档进⾏分词或者是N-gram处理,然后进⾏去重得到词典,假设我们有⼀个⽂档:深度学习,那么进⾏one-hot处理后的结果如下:
token one-hot encoding
大话西游一生所爱深1000
度0100
学0010
习0001
⼿⼯进⾏one-hot编码:
from  sklearn .externals import  joblib # 导⼊⽤于对象保存与加载的joblib
from  keras .preprocessing .text import  Tokenizer # 导⼊keras 中的词汇映射器Tokenizer
vocab = {"周杰伦", "陈奕迅", "王⼒宏", "李宗盛", "周华健", "⿅晗"} # 假定vocab 为语料集所有不同词汇集合
t = Tokenizer (num_words =None , char_level =False ) # 实例化⼀个词汇映射器对象
t .fit_on_texts (vocab ) # 使⽤映射器拟合现有⽂本数据
for  token in  vocab :
zero_list = [0]*len (vocab )
token_index = t .texts_to_sequences ([token ])[0][0] - 1 # 使⽤映射器转化现有⽂本数据, 每个词汇对应从1开始的⾃然数;返回样式如: [[2]], 取出其中的数字需要使⽤[0][0]
zero_list [token_index ] = 1
print (token , "的one-hot 编码为:", zero_list )
tokenizer_path = "./Tokenizer" # 使⽤joblib ⼯具保存映射器, 以便之后使⽤
joblib .dump (t , tokenizer_path )
打印结果:
⿅晗 的one -hot 编码为: [1, 0, 0, 0, 0, 0]
王⼒宏 的one -hot 编码为: [0, 1, 0, 0, 0, 0]
李宗盛 的one -hot 编码为: [0, 0, 1, 0, 0, 0]
陈奕迅 的one -hot 编码为: [0, 0, 0, 1, 0, 0]
周杰伦 的one -hot 编码为: [0, 0, 0, 0, 1, 0]
周华健 的one -hot 编码为: [0, 0, 0, 0, 0, 1]one-hot编码的优劣势:优势:操作简单,容易理解.
劣势:完全割裂了词与词之间的联系,⽽且在⼤语料集下,每个向量的长度过⼤,占据⼤量内存.
正因为one-hot编码明显的劣势,这种编码⽅式被应⽤的地⽅越来越少,取⽽代之的是稠密向量的表⽰⽅法word embedding
2、Word Embedding
真皮沙发十大品牌
word embedding是深度学习中表⽰⽂本常⽤的⼀种⽅法。和one-hot编码不同,word embedding使⽤了浮点型的稠密矩阵来表⽰
token。根据词典的⼤⼩,我们的向量通常使⽤不同的维度,例如100,256,300等。其中向量中的每⼀个值是⼀个参数,其初始值是随机⽣成的,之后会在训练的过程中进⾏学习⽽获得。
如果我们⽂本中有20000个词语,如果使⽤one-hot编码,那么我们会有20000*20000的矩阵,其中⼤多数的位置都为0,但是如果我们使⽤word embedding来表⽰的话,只需要20000* 维度,⽐如20000*300
形象的表⽰就是:
token num vector
词1
0 ,其中  表⽰维度(dimension)词2
1词3
2…
….…词m m ,其中  表⽰词典的⼤⼩
我们会把所有的⽂本转化为向量,把句⼦⽤向量来表⽰
但是在这中间,我们会先把token使⽤数字来表⽰,再把数字使⽤向量来表⽰。即:token---> num ---->vector
在这⾥插⼊图⽚描述
[w ,w ,w ...w ]1112131N N [w ,w ,w ...w ]2122232N [w ,w ,w ...w ]3123333N [w ,w ,w ...w ]m 1m 2m 3mN m
⽂本张量表⽰⽅法 ---->参考:
使⽤fasttext⼯具实现word2vec的训练和使⽤:参考资料: