词向量与相关应用

一、基础知识

计算机没有人类的先验知识,如何理解文字,如何让实现文本分类,必须找到一套方法或方式对这些我们人类造成的词去表达和表式。一是从大量的预料中,拿到一些可以对它的含义表达的一些表达方式,二是文本是标记性的语言没办法去做机器学习,转成计算机可以理解的数值型的向量

词编码---> N-gram, TFIDF--->word2vec

Nlp常见问题:自动摘要、指代消解、机器翻译、词性标注、分词(中文、日文等)、主题识别、文本分类。 

传统:基于规则

现代:基于统计机器学习 HMM, CRF, SVM, LDA, CNN….”规则“隐含在模型参数里

词编码

词编码需要保证词的相似性,如果每个词都给一个码就不能保证识别子类、近义词等,比如青蛙和蟾蜍等等

我们希望编码方式可以表达同样含义的词在向量空间里面分布相似,例如下面假设的二维空间。

 

向量空间子结构

每个词一定是空间中的某个点,期望词向量能捕捉到词和词之间的相对关系

VKing – Vqueen +Vwomen = Vman

VParis – VFrance +VGerman = VBerlin

最终目标,词向量表示作为机器学习、特别是深度学习的输入和表示空间

英语里面自然语言处理的库NLTK,他会建立很大一个字典,根据专家构建出来的权威的东西,比如猫,是一个动物,有胎生,弹跳性等上位词。但是会有很多问题,不能分辨细节的差别、需要大量人为劳动、主管、无法发现新词、难以精确计算词之间的相似度

 

二、离散表示

离散表示:one-hot表示

很早之前的词编码的方式,建索引,one-hot,每个单词都有唯一索引,在词典中的顺序和在句子中的顺序没有关联。先建索引,再one-hot表示。

这种方式非常吃空间,维度非常非常高,如果每个词给一个编码,会做一个高频统计,只表示3000或4000个高频词,其他的词都用一个维度表示。

 

离散表示:bag of words

刚刚方式可以表达词,但最终目标是表达文本。文档的向量表示可以直接将各词的词向量表示加和。对应维度下面填充数字,表示这个数字出现了多少次。

 

from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer()
#四段语料
corpus = ["i come to China to travel",
                “This is  a car popular in china”,
                "i love tea and apple",
                "the work is  to write some papers in science"]
print vectorizer.fit_transform(corpus)
print vectorizer.fit_transform(corpus).toarray()
print vectorizer.get_feature_names()

离散表示:TF-IDF

在搜索引擎中,常用到词权重,从而引申出TF-IDF。

 

 1 # 读入文本
 2 with open('./nlp_text1.txt') as f3:
 3        res1 = f3.read()
 4 
 5 with open('./nlp_text3.txt') as f4:
 6        res2 = f4.read()
 7 
 8 #停用词
 9 #从文件导入停用词表                                                  
10 stpwrdpath = "stop_words.txt"
11 stpwrd_dic = open(stpwrdpath, 'rb')
12 stpwrd_content = stpwrd_dic.read()
13 #将停用词表转换为list  
14 stpwrdlst = stpwrd_content.splitlines()
15 stpwrd_dic.close()
16 
17 # 向量化,TF-IDF和标准化 当然,还可以处理停用词
18 from sklearn.feature_extraction.text import TfidfVectorizer
19 corpus = [res1,res2]
20 vector = TfidfVectorizer(stop_words=stpwrdlst)
21 tfidf = vector.fit_transform(corpus)
22 print tfidf
23 
24 wordlist = vector.get_feature_names()#获取词袋模型中的所有词  
25 # tf-idf矩阵 元素a[i][j]表示j词在i类文本中的tf-idf权重
26 weightlist = tfidf.toarray()  
27 #打印每类文本的tf-idf词语权重,第一个for遍历所有文本,第二个for便利某一类文本下的词语权重
28 for i in range(len(weightlist)):  
29     print "-------第",i,"段文本的词语tf-idf权重------"  
30     for j in range(len(wordlist)):  
31         print wordlist[j],weightlist[i][j]

离散表示:语言模型 Bi-gram和N-gram

上面两个表示方式都没有考虑词的顺序。Bi-gram和N-gram考虑了词的顺序,但是缺点是词表膨胀。

 

离散表示的问题:

无法衡量词向量之间的关系(没有捕获文本的含义);词表维度随着语料库增长膨胀;n-gram词序列随语料库膨胀更快;数据稀疏问题。

对于词袋模型的稀疏问题可以用常用的文本降维方法是Hash Trick。在Hash Trick中,首先定义一个Hash后对应的哈希表,这个哈希表的维度会远远小于词汇表的特征维度,因此可以看成是降维。具体的方法是,对任意一个特征,使用用Hash函数找到对应哈希表的位置,然后将该特征对应的词频统计值累加到该哈希表位置。在scikit-learn的HashingVectorizer类中,实现了基于signed hash trick的算法。

from sklearn.feature_extraction.text import HashingVectorizer
vectorizer2 = HashingVectorizer(n_features=6,norm=None)
print vectorizer2 .fit_transform(corpus)

三、分布式连续表示

分布式表示(Distributed representation)

 

1957年firth提出,用一个词附近的其他词来表示该词,这被认为是现代统计自然语言处理中最有创见的想法之一。计算机可以看很多语料,比如发现banking经常和经济这类词放到一起,基于这种思路,就有很多人提出了不同的解决思路。

共现矩阵(Cocurrence matrix)

即两个词同时出现。Word-Document的共现矩阵主要用于发现主题,用于主题模型,如LSA(latent semantic analysis)

这时候就有一个局域窗的概念,就是在一个范围内看共现的单词。局域窗中的word-word共现矩阵可以挖掘语法和语义信息。

Window length设为1(一般设为5-10)

使用对窗函数(左右window length都为1)

将共现矩阵行作为词向量。

下图为这三句话的共现矩阵,假设左右窗口为1,i旁边左右窗口中like出现2次,enjoy出现1次。这时候的向量表示用的是共现矩阵的方式。

 

优势:能表示出来词的相关度。把周边朋友拿过来了,上下文捕捉到了

缺点:向量维数随着词典大小线性增长;存储整个词典的空间消耗非常大;一些模型如文本分类模型会面临稀疏性问题;模型会欠稳定(加了新的句子,统计的频率就不一样)。

解决上面维度的缺陷,最直接的想法是降维,用SVD对共现矩阵向量做降维,取    U矩阵里面的值。该想法依然有问题,计算量随语料库和词典增长膨胀太快,对X(m*n)维的矩阵,计算量o(n^3);难以为词典中新加入的词分配词向量。与其他深度学习模型框架差异大(已经再原始数据上处理了,可能不是deeplearnning想要的输入方式)。

Import numpy as np

la = np.linalg

x = np.array([

[0,2,1,0,0,0,0,0],

[2,0,0,1,0,0,0,0],

[1,0,0,1,,0,0,1,0]

])

U, S, Vh = la.svd(X, full_matrices=False)

四、WORD2VEC

NNLM(neural network language model)2003年提出word2vec前身

直接从语言模型出发,将模型最优化过程转化为求词向量表示的过程。前向窗函数,由N-1个词推断下一个词的概率,会遍历整个语料库。

使用了非对称的前向窗函数,窗长度为n-1,滑动窗口遍历整个语料库求和,

与标准答案的相近度,希望越大越好。

要求概率P满足归一化条件,这样不同位置t处的概率才能相加,即:

对所有的词做一个稀疏的向量表示,前n-1个词去预测下一个词。 NNLM只有1个隐层。最后W假设是1*8000(对1个词的描述),假设最后的向量是个500维的,那C就是80000*500。先通过投影矩阵(先随机初始化)做投影,只是从W里面选出一行或者一列,然后到一个隐层,然后再到softmax,最后完成拼接。最后的维度,取决于你的n,如果你要用前10个词预测,那应该是10*500=5000维。输出层softmax,我们希望拿到的概率值尽量的高,可以加上一个负号然后用BP+SDG可以完成优化,一旦优化完了,投影矩阵也就是最好的稠密向量表示。

 

因为是神经网络,所以需要大量的数据,每个训练样本的复杂度为N*D+N*D*H+H*V,因此在这个基础上去做了简化。

 Word2Vec实际上是两种不同的方法:Continuous Bag of Words (CBOW) 和 Skip-gram。

这两种方法都利用人工神经网络作为它们的分类算法。起初,每个单词都是一个随机 N 维向量。经过训练之后,该算法利用 CBOW 或者 Skip-gram 的方法获得了每个单词的最优向量。

 Word2vec:CBOW(连续词袋)

Continue bag of words由周边的n个词,去推中间的1个词。

如何简化?

试试无隐层。

使用双向上下文窗口。

上下文词序无关。

输入层直接使用低维稠密表示。

投影层简化为求和(平均)

 

最后是一个softmax,类似于多分类的softmax,也需要去完成一个全连接的计算,拼接,如果词表是40W,500*40W你就需要有这样一个连接,消耗太大,所以要处理,有两种方式:

一种是层次softmax。40W词是平铺开来的,意思是和40w词都要有连接,对于平铺开来的结构如果要压缩空间是层叠起来的结构,使用huffman树对原本文本语料进行编码,根据出现频次的高低。边上的权重可以共享。根据语料在这个huffman树上找到路径(每个节点就是个二分类),求出这条路径上的概率相加,使其最大,就把刚刚平铺的变成了层叠的结构。

  

另一种是负例采样(工业上用的多一些)。由前后的词预测第t个词,可以将第t个词当成是正确的正样本,其他的作为负样本(40w-1),负样本的量太大了,所以我们可以去对这些负样本去采样。这个采样是要有技巧的,保证采样完的东西和原本的相近度很高。Google在做这个事情的时候想了个办法,拉出一个长度为1的小段,切成了10^8次方等分,然后按照词出现的词频的3/4划分占多少线段,在从空中抛色子,色子有10^8面,那个面朝上,查一查这个数落在哪一段,就把这一段的词取出来。之后就可以train一个softmax。

 

Word2vec:Skip-Gram(连续词袋)

上面是由周边的词推断中间的词,而Skip-Gram是中间的词推断周边的词,其他的和CBOW基本一致。语料非常大的话Skip-Gram的结果稍微比CBOW好一点

 

Word2vec存在的问题

对每个local context window单独训练,没有利用包含在global co-currence矩阵中的统计信息。改进方法:Glove

对多义词无法很好的表示和处理(比如苹果手机和苹果),因为使用了唯一的词向量。

Glove可以利用全局的信息,如果你需要一个对词表示的很好的词向量,可以试试Glove有开源的专门的库。但是深度学习里面还是用word2vec比较多,因为词嵌入这种方式你是可以可以作为嵌入层,直接做一个端到端的模型,嵌入的词表和目标直接关联的。

词嵌入效果评估:词类比任务。

词嵌入效果评估:词相似度任务。

词嵌入效果评估:作为特征用于CRF。

 

 四、工具

1.Google word2vec

Git clone https://github.com/dav/word2vec

cd word2vec/src

Make

2.Python库

Genism

easy_install -U genism或pip install –upgrade

示例代码 https://www.zybuluo.com/hanxiaoyang/note/472184

word2vec作为此的初始输入,后面可以接各种各样的模型

word2vec + CNN尤其是建立成端到端的模型

电商情感分析 snownlp

参考博客 

http://mp.weixin.qq.com/s?__biz=MzIxODM4MjA5MA==&mid=2247485748&idx=1&sn=daca1a059a51e3a2265a49c34faa3fe9&chksm=97ea2351a09daa4720c84c139751b1515c5447dac4d92741b9a7a3583a51aadbd758db013b26&scene=21#wechat_redirect 

原文地址:https://www.cnblogs.com/fionacai/p/8268202.html