文本向量化(理论篇)

本文介绍常见的文本表示模型,One-hot、词袋模型(BOW)、TF-IDF、N-Gram和Word2Vec

离散表示

One-hot编码

one-hot编码是常用的方法,我们可以用one-hot编码的方式将句子向量化,大致步骤为:

  • 用构造文本分词后的字典
  • 对词语进行One-hot编码

John likes to watch movies. Mary likes too

John also likes to watch football games.

上面的两句话分词后可以构造一个字典,字典内容如下,字典的键是词语,值是ID

{"John": 1, "likes": 2, "to": 3, "watch": 4, "movies": 5, "also": 6, "football": 7, "games": 8, "Mary": 9, "too": 10}

我们可以根据ID值对每个词语进行向量化,用0和1代表这个词是否出现

# John
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# too
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

one-hot 词向量构造起来简单,但通常不是一个好的选择,它有明显的缺点

  • 维数过高。我们这里只有短短的2句话,每个词语已经是一个10维的向量了,随着语料的增加,维数会越来越大,导致维数灾难
  • 矩阵稀疏。利用One-hot编码的另一个问题就是矩阵稀疏,从上面也可以看到,每一个词向量只有1维是有数值的,其他维上的数值都为0
  • 不能保留语义。用这种方式得到的结果不能保留词语在句子中的位置信息, “我爱你” 和 “你爱我” 的向量化结果并没有什么不同。

词袋(BOW)模型

词袋模型(Bag-of-words model,BOW),BOW模型假定对于一个文档,忽略它的单词顺序和语法、句法等要素,将其仅仅看作是若干个词汇的集合,文档中每个单词的出现都是独立的,不依赖于其它单词是否出现。

John likes to watch movies. Mary likes too

John also likes to watch football games.

使用之前同样的例子,跟前面一样,将上面的两句话中看作一个文档集,列出文档中出现的所有单词(忽略大小写与标点符号),构造一个字典

{"John": 1, "likes": 2, "to": 3, "watch": 4, "movies": 5, "also": 6, "football": 7, "games": 8, "Mary": 9, "too": 10}

再用再将句子向量化,维数和字典大小一致,第 $i$ 维上的 数值 代表 ID 为 $i$ 的词语在这个句子里出现的频次

# 第一个文本
[1, 2, 1, 1, 1, 0, 0, 0, 1, 1]
# 第二个文本
[1, 1, 1, 1, 0, 1, 1, 1, 0, 0]

以第一个文本的向量化结果 [1, 2, 1, 1, 1, 0, 0, 0, 1, 1] 为例,2在第二维上,ID为2的词语是likes,在第一个文本中出现了2次,所以第二维上的数值是2

这种方式不像one-hot编码那样导致维数非常大,但也有自己的缺点

  • 不能保留语义:不能保留词语在句子中的位置信息,“你爱我” 和 “我爱你” 在这种方式下的向量化结果依然没有区别。“我喜欢北京” 和 “我不喜欢北京” 这两个文本语义相反,利用这个模型得到的结果却能认为它们是相似的文本。
  • 维数高和稀疏性:当语料增加时,那么维数也会不可避免的增大,一个文本里不出现的词语就会增多,导致矩阵稀疏

TF-IDF

TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术。TF意思是词频(Term Frequency),IDF意思是逆文本频率指数(Inverse Document Frequency)。

字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。一个词语在一篇文章中出现次数越多, 同时在所有文档中出现次数越少, 越能够代表该文章。

TF-IDF公式如下:

 

$TF(t,d)$表示 语t 在 文档d 中出现的频率,$IDF(t)$是逆文本频率指数,它可以衡量 单词t 用于区分这篇文档和其他文档的重要性。IDF的公式如下,分母加1是为了避免分母为0

比如在10篇文档中,1篇是猴子的,9篇是关于人的,关于人的文章中不出现 “尾巴” 这个词语,10篇文章中都出现 “嘴巴” 这个词语,那么 “尾巴” 这个词在这些文章中就很有区分度。从公式的角度也很容易看出。以10为底数的话,$IDF(尾巴)$ = 0.70, $IDF(嘴巴)$ = -0.04,说明 “尾巴” 重要性更高点,它有区分性。

前面说的缺点依然存在,它依然不能保留词语在句子中的位置关系。

N-Gram

N-Gram语言模型的思想就是,给定一串字母,下一个最大可能出现的词语是什么?比如 “今天你”,后面跟 “吃饭” 可能性大,但跟着 “后天” 的可能性就很小。

N=1时称为unigram,N=2称为bigram,N=3称为trigram,假设下一个词的出现依赖它前面的一个词,即 bigram,假设下一个词的出现依赖它前面的两个词,即 trigram,以此类推。

以下面的文本为例

你帮我

我帮你

它的bigram依次为:

你,你帮,帮,帮我,我
我,我帮,帮,帮你,你

同样地,我们可以构造一个字典

{"": 1, "你帮"; 2, "": 3"帮我": 4, "": 5, "我帮": 6, "帮你": 7}

向量化结果可以表示为

# 第一个文本
[1, 1, 1, 1, 1, 0, 0]

# 第二个文本
[1, 0, 1, 0, 1, 1, 1]

N-Gram基于一个假设:第n个词出现与前n-1个词相关,而与其他任何词不相关(这也是隐马尔可夫当中的假设)。整个句子出现的概率就等于各个词出现的概率乘积,公式如下:

上面的表达式并不好计算,引入马尔科夫假设,那么可以将式子写成

马尔可夫链(Markov chain)为状态空间中经过从一个状态到另一个状态的转换的随机过程。该过程要求具备“无记忆”的性质:下一状态的概率分布只能由当前状态决定,而与之前的状态无关

 特别地,对unigram,有

对bigram,有

  对trigram,有

 N-Gram考虑了词的顺序,信息量更充分

缺点是随着N的增大,词表迅速膨胀,数据出现大量稀疏的问题。

总结

由于存在以下的问题,对于一般的NLP问题,是可以使用离散表示文本信息来解决问题的,但对于要求精度较高的场景就不适合了。

  • 无法衡量词向量之间的关系。
  • 词表的维度随着语料库的增长而膨胀。
  • n-gram词序列随语料库增长呈指数型膨胀,更加快。
  • 离散数据来表示文本会带来数据稀疏问题,导致丢失了信息,与我们生活中理解的信息是不一样的。

分布式表示

科学家们为了提高模型的精度,又发明出了分布式的表示文本信息的方法。

用一个词附近的其它词来表示该词,这是现代统计自然语言处理中最有创见的想法之一。当初科学家发明这种方法是基于人的语言表达,认为一个词是由这个词的周边词汇一起来构成精确的语义信息。就好比,物以类聚人以群分,如果你想了解一个人,可以通过他周围的人进行了解,因为周围人都有一些共同点才能聚集起来。

共现矩阵

共现矩阵顾名思义就是共同出现的意思,词文档的共现矩阵主要用于发现主题(topic),用于主题模型,如LSA。

局域窗中的word-word共现矩阵可以挖掘语法和语义信息,例如:

I like deep learning.
I like NLP.
I enjoy flying.

有以上三句话,设置滑窗(对称窗口)为2,可以得到一个词典:{"I like","like deep","deep learning","like NLP","I enjoy","enjoy flying","I like"}。

我们可以得到一个共现矩阵(对称矩阵):

中间的每个格子表示的是行和列组成的词组在词典中共同出现的次数,也就体现了共现的特性。比如例如:“I like”出现在第1,2句话中,一共出现2次,所以=2。 对称的窗口指的是,“like I”也是2次

存在的问题:

  • 向量维数随着词典大小线性增长。
  • 存储整个词典的空间消耗非常大。
  • 一些模型如文本分类模型会面临稀疏性问题。
  • 模型会欠稳定,每新增一份语料进来,稳定性就会变化。

Word2Vec

谷歌2013年提出的Word2Vec是目前最常用的词嵌入模型之一。Word2Vec实际 是一种浅层的神经网络模型,它有两种网络结构,分别是CBOW(Continues Bag of Words)连续词袋Skip-gram

CBOW

CBOW是一个三层神经网络,特点是输入已知上下文,输出对当前单词的预测。 CBOW通过中间词来预测窗口中上下文词出现的概率模型,把中间词当做y,把窗口中的其它词当做x输入,x输入是经过one-hot编码过的,然后通过一个隐层进行求和操作,最后通过激活函数softmax,可以计算出每个单词的生成概率,接下来的任务就是训练神经网络的权重,使得语料库中所有单词的整体生成概率最大化,而求得的权重矩阵就是文本表示词向量的结果。。

举一个例子,我们有以下文本

I drink coffee everyday

假设我们输入为 I, drink, everyday,那么我们训练的神经网络要使 coffee 的输出概率最大。首先,我们将原来的文本的单词用One-hot编码表示,如下图所示

 

初始化输入权重矩阵 $W$ 和输出权重矩阵 $W^{'}$,利用这个权重矩阵W和One-hot编码完的向量相乘,可以得到唯一的向量 $V$,相当于根据One-hot编码中1的位置取出W中的对应的列,除非两列完全相同,否则得到的向量不会是一样的。

我们这里有3个输入值,将3个输入值与 $W$ 相乘得到的向量相加做平均,得到隐藏层向量

   隐藏层向量再乘以输出权重矩阵 $W^{'}$ ,得到一个输出向量

 对输出向量做softmax,得到输出概率

Skip-Gram

Skip-Gram与CBOW相反,即已知某个词语,预测周围的词语。通过当前词来预测窗口中上下文词出现的概率模型,把当前词当做 $x$,把窗口中其它词当做 $y$,依然是通过一个隐层接一个Softmax激活函数来预测其它词的概率。

以下图举例,我们选定句子“The quick brown fox jumps over lazy dog”,设定我们的窗口大小为2(window_size=2),也就是说我们将输入词前后各两个词和输入词进行组合作为训练样本。下图中,蓝色代表input word,方框内代表位于窗口内的单词。

以第一条为例,The为输入词,但是The开头,前面没有词跟它组合,所以只能和后面两个单词分别组合。

当quick输入时,它前面只有1个单词,所以一共只有3个组合。

从brown开始,前面才会有2个及以上的单词,所以从这里开始有4个组合。

 

 我们的模型将会从每对单词出现的次数中习得统计结果。例如,我们的神经网络可能会得到更多类似(“可乐“,”百事“)这样的训练样本对,而对于(”可乐“,”酱油“)这样的组合却看到的很少。因此,当我们的模型完成训练后,给定一个单词”可乐“作为输入,输出的结果中”百事““要比”酱油“的概率高。

加速优化方法

有Hierarchical Softmax(层次Softmax)和Negative Sample(负采样)两个加速方法,参考以下链接

参考资料

https://github.com/mantchs/machine_learning_model/tree/master/Word2Vec

https://www.jianshu.com/p/f8300129b568

https://blog.csdn.net/weixin_43112462/article/details/88669902

https://blog.csdn.net/lxg0807/article/details/78615917

https://www.cnblogs.com/bep-feijin/p/9430164.html

https://blog.csdn.net/yu5064/article/details/79601683

https://www.jianshu.com/p/471d9bfbd72f

https://www.zhihu.com/question/44832436

http://www.dataguru.cn/article-13488-1.html

posted @ 2019-09-05 22:12  那少年和狗  阅读(5997)  评论(1编辑  收藏