word2vec学习笔记之文本向量化概述


在NLP的处理中,我们需要讲文本输入到模型中处理,实现分类识别,文本生成或者翻译等工作。而模型是无法知道一个纯粹的文本是什么意思的,模型的输入只能是数字,比如连续型的小数或则离散的整数。而对于文本之类的无法直接用数字表示的数据可以通过一下几种方式处理。

1. one-hot

在机器学习中,我们经常使用该方法处理一些类别型的数据。比方说,在预测放假的时候,有一微特征表示几线城市,有“一线”,“新一线”,“二线”,“三线”,“四线”,“其他”等,那么当某一个特征的值为“二线”的时候,就可以表示为[0, 0, 1, 0, 0, 0]。在实现的时候,可使用sklearn进行one-hot编码。

# 例子来自sklearn的官方例子,https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html
>>> from sklearn.preprocessing import OneHotEncoder
>>> enc = OneHotEncoder(handle_unknown='ignore')
>>> X = [['Male', 1], ['Female', 3], ['Female', 2]]
>>> enc.fit(X)
OneHotEncoder(handle_unknown='ignore')
>>> enc.categories_
[array(['Female', 'Male'], dtype=object), array([1, 2, 3], dtype=object)]
>>> enc.transform([['Female', 1], ['Male', 4]]).toarray()
array([[1., 0., 1., 0., 0.],
       [0., 1., 0., 0., 0.]])

在文本处理中,可以以此表vocab中的所有词作为类别集合,按照文本所需处理的词进行one-hot编码,用于one-hot处理。

2. tfidf

然而,使用one-hot编码无法表示词的重要性。比如一个文本嗯,我是程序员中,经过分词之后是["嗯",“我”,“是”, "程序员"], 显然这句话中,程序员这几个词比重要,但是在经过one-hot处理之后,是看不出来这几个词之间的区别的。而使用tfidf方式就能够表示词的重要性。
tfidf的方法,是根据一个词在一篇文本中出现的次数,以及该词在所有文本中出现的次数来计算的,用于表示一个词的重要程度。比如某词的ifidf的计算公式如下 t f = 某 词 在 文 本 中 出 现 的 次 数 该 文 本 的 词 的 总 数 tf=\frac{某词在文本中出现的次数}{该文本的词的总数} tf=
i d f = l o g 语 料 中 的 文 本 总 数 含 有 该 词 的 文 本 总 数 + 1 idf=log\frac{语料中的文本总数}{含有该词的文本总数+1} idf=log+1
t f i d f = t f ∗ i d f tfidf=tf*idf tfidf=tfidf直观的理解就是,一个词在某个文本中出现的次数越多,那么该词在该文本中就越重要(即 t f tf tf),但是如果一个词在语料的所有文本中都出现过,那么该词就不那么重要了,比如,之类的词可能在语料的很多文本中出现过,但是这些词是不重要的(即 i d f idf idf),于是就可以使用 t f ∗ i d f tf*idf tfidf来表示一个词在所在文本中的重要新。
而理论上对于每一个文本,都可以计算词表vocab中所有词在该文本中的 t f i d f tfidf tfidf(如果某次在该文本中没出现过,那么就可以直接以0表示重要性),那么对于每一个文本,就可以用一个词表长度的向量来表示。计算一个文本的tfidf值,同样可以调用sklearn。

# 例子来自sklearn的官方例子,https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html
>>> from sklearn.feature_extraction.text import TfidfVectorizer
>>> corpus = [
...     'This is the first document.',
...     'This document is the second document.',
...     'And this is the third one.',
...     'Is this the first document?',
... ]
>>> vectorizer = TfidfVectorizer()
>>> X = vectorizer.fit_transform(corpus)
>>> print(vectorizer.get_feature_names())
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
>>> print(X.shape)
(4, 9)

3. n-gram

使用 t f i d f tfidf tfidf虽然能够表示一个词在文本中的重要程度,但是却无法表示词的先后顺序。比如鸣人喜欢雏田雏田喜欢鸣人,这是两句不一样的话,但是在 t f i d f tfidf tfidf的表示方法中,这两句话却会被表示成一样的向量。如果我们能够在文本表示中添加词的先后顺序的信息,就能一定程度的解决这个问题。
因此,我们可以使用n-gram来表示文本。n-gram,就是把文本分词之后,以n个词为一个单元来进行处理。比如,以bi-gram(即n=2)为例,在上述的两句话中,经过分词之后,得到的均是[鸣人,喜欢, 雏田],而第一句使用bi-gram表示结果为[鸣人喜欢,喜欢雏田],第二句的表示结果为[雏田喜欢,喜欢鸣人],这样两句话的表示结果就不一样了。
但是,使用n-gram表示方法,每一个文本档的表示结果就不是词表的大小,而是词表大小vocab_size的n次方。这就使得每一个文本的表示结果非常长,且非常稀疏。

4. NNLM

后来,一些大牛们就想到了使用神经网络来训练表示文本的向量,于是就有了NNLM(Feedforward Neural Net Language Mode)。NNLM的网络结构如下:
NNLM
NNLM,Feedforward Neural Net Language Mode,翻译过来就是“前向神经网络语言模型”,这是一个语言模型,文本的词向量表示是其中间产物。
如上图所示,NNLM是使用文本中的某一个词的前N-1个词来预测该词。NNLM的预测流程如下:

  1. 获取当前词的前N-1个词,将这N-1个词经过shape=vocab_size*embedding_size的矩阵 C C C转化伟相应词的向量,有N-1个词,于是就得到了N-1个向量
  2. 将这N-1个向量进行concat拼接,将拼接后的向量经过tanh的非线性变化之后,在经过一个全连接的隐藏层
  3. 然后再经过一个softmax层输出结果。输出概率最大的神经元对应的词,即为预测的当前词。

NNLM为语言模型,而我们取其中的矩阵 C C C作为我们的词向量矩阵,矩阵中第 i i i行的向量,就是词表中第 i i i个词的向量化结果。
在NNLM的训练过程中,时间复杂度为 Q = N ∗ D + N ∗ D ∗ H + H ∗ V Q=N*D+N*D*H+H*V Q=ND+NDH+HV其中N为上述过程中的N,D为词向量的大小,即为上述过程中的embedding_size,H为隐藏层的大小,V为词表大小。

5. word2vec

上述的计算的时间复杂度也比较大,尤其是在隐藏层中消耗比较大的计算资源,为此, T o m a s M i k o l o v Tomas Mikolov TomasMikolov提出了新的词向量训练模型wor2vec用于简化计算,word2vec有CBOW和n-gram两种形式,并且针对词表比较大的情况又提出了hierarchical softmax和nagative sampling两种优化方法。
word2vec
上图即为word2vec的两种形式,具体对于这两种形式的介绍,待下一篇再进行介绍。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值