机器学习之word2vec

1、词向量基础

词向量维度为整个词汇表的大小,对于表中的词,将对应位置置为1,其余位置置为0即可。如由5个词(king, queen, man, woman, child)组成的词汇表,对于queen单词在词汇表中的顺序为2,那么它的词向量可表示为(0, 1, 0, 0, 0),woman的词向量可表示为(0, 0, 0, 1, 0),这种词向量的编码方式叫做1-of-N 编码或者one hot编码。

one hot编码较为简单,但存在很多缺陷

  • 当词汇表非常大时,每个词都用百万维的向量表示,将造成维度灾难。这样的向量除了一个位置为1,其余位置都为0,表达效率不高。

词袋模型有着如下3点缺点

  • 无法识别出词汇之间的相似性;
  • 不考虑词与词之间的顺序;
  • 基于词袋模型(包括one-hot、TF - IDF)得到的特征是离散稀疏的。

我们想采用一种方式:将每个词都映射到一个较短的词向量上来。所有的这些词向量就构成了向量空间,进而可以用普通的统计学的方法来研究词与词之间的关系。这个较短的词向量维度一般需要我们在训练时自己来指定。

可见我们只要得到了词汇表里所有词对应的词向量,那么我们就可以神经网络语言模型将高维稀疏向量映射到低维。

2、word2vec原理

2.1 CBOW与Skip-Gram用于神经网络模型

2.1.1 CBOW与Skip-Gram用于神经网络

  • CBOW(Continuous Bag-of-Words)模型:
    CBOW模型的训练输入是某一个特征词的上下文相关的词对应的词向量,而输出就是这特定的一个词的词向量。比如下面这段话,我们的上下文大小取值为4,特定的这个词是"learning",是我们需要的输出词向量,上下文对应的词有8个,前后各4个,这8个词是我们模型的输入。由于CBOW使用的是词袋模型,因此这8个词都是平等的,也就是不考虑他们和我们关注的词之间的距离大小,只要在我们上下文之内即可。
    在这里插入图片描述
    输入是8个词向量,输出是所有词的softmax概率(训练的目标是期望训练样本特定词对应的softmax概率最大),对应的CBOW神经网络模型输入层有8个神经元,输出层有词汇表大小个神经元。隐藏层的神经元个数我们可以自己指定。通过DNN的反向传播算法,我们可以求出DNN模型的参数,同时得到所有的词对应的词向量。
  • Skip-Gram模型:
    Skip-Gram模型和CBOW的思路是反着来的,即输入是特定的一个词的词向量,而输出是特定词对应的上下文词向量。还是上面的例子,我们的上下文大小取值为4, 特定的这个词"learning"是我们的输入,而这8个上下文词是我们的输出。
    输出是softmax概率排前8的8个词,对应的Skip-Gram神经网络模型输入层有1个神经元,输出层有词汇表大小个神经元。隐藏层的神经元个数我们可以自己指定。通过DNN的反向传播算法,我们可以求出DNN模型的参数,同时得到所有的词对应的词向量。这样当我们有新的需求,要求出某1个词对应的最可能的8个上下文词时,我们可以通过一次DNN前向传播算法得到概率大小排前8的softmax概率对应的神经元所对应的词即可。

2.1.2 CBOW vs Skip-gram区别

  • 首先CBOW是利用上下文预测中心词,Skip-gram是利用中心词预测上下文;

  • Skip-gram训练时间长,但是对低频词(生僻词)效果好;CBOW训练时间短,对低频词效果比较差。
    在这里插入图片描述
    对于区别中的第二点解释一下:

  • CBOW是利用上下文预测中心词,训练过程是从输出的中心词的loss来学习上下文的词向量。V个中心词,对应V个训练样本,一共学习V次就结束了。训练复杂度O(V),训练时间较快。而且上下文词向量是取得平均值,一视同仁的对待,那么低频词训练的少,而且也没有特殊处理,当然效果不好。

  • Skip-gram利用中心词预测上下文,假设我们考虑前后共K个上下文,那么每一个上下文都会修正一次中心词的词向量表达,训练复杂度是O(KV)训练时间会变长。但是低频词也有多个上下文,相比于CBOW,其词向量会被多次修正,自然效果也就好一些。

2.2 word2vec基础之霍夫曼树

word2vec也使用了CBOW与Skip-Gram来训练模型与得到词向量,但是并没有使用传统的DNN模型。最先优化使用的数据结构是用霍夫曼树来代替隐藏层和输出层的神经元,霍夫曼树的叶子节点起到输出层神经元的作用,叶子节点的个数即为词汇表的小大。 而内部节点则起到隐藏层神经元的作用。

  • 霍夫曼树的建立过程
    输入:权值为( w 1 , w 2 , . . . , w n w_1, w_2, ..., w_n w1,w2,...,wn)的 n n n个节点;
    输出:对应的霍夫曼树。
    1)将( w 1 , w 2 , . . . , w n w_1, w_2, ..., w_n w1,w2,...,wn)看做是n棵树的森林,每个树仅有一个节点;
    2)在森林中选择根节点权值最小的两棵树进行合并,得到一个新树,这两个树分布作为新树的左右子树,新树的节点权重为左右子树的权重之和;
    3)将之前权值最小的两棵树删除,并把新树加入森林;
    4)重复步骤2)和步骤3)直到只有一棵树为止。

  • 例子:(a,b,c,d,e,f)共6个节点,节点的权值分布是(20,4,8,6,16,3)。
    首先是最小的b和f合并,得到的新树根节点权重是7。此时森林里5棵树,根节点权重分别是20,8,6,16,7。此时根节点权重最小的6,7合并,得到新子树,依次类推,最终得到下面的霍夫曼树。
    在这里插入图片描述
    得到霍夫曼树后,我们可以对叶子节点进行霍夫曼编码,由于权重高的叶子节点越靠近根节点,而权重低的叶子节点会远离根节点,这样高权重节点编码值较短,低权重节点编码较长。这样保证带权路径最短,即符合越常用的词拥有更短的编码。
    一般对于霍夫曼树的节点(根节点除外),约定左子树编码为0,右子树编码为1,即可以得到上图中节点c的编码为00。
    在word2vec中,约定编码方式和上面的例子相反,即约定左子树编码为1,右子树编码为0,同时约定左子树的权重不小于右子树的权重。

2.3 word2vec基础之Hierarchical Softmax的模型

传统的神经网络语言模型,包含三层:输入层、隐藏层和输出层(softmax层),存在最大的问题是从隐藏层到输出的softmax层计算量较大,因为要计算所有词的softmax概率,还要寻找最大值,如下图所示,V是词汇表的大小:

word2vec做了如下改进:
输入层→隐藏层:没有采用线性变换+激活函数的方法,而是采用简单的对所有输入词向量求和取平均的方法;例如多个向量变为一个向量:(1,2,3,4),(9,6,11,8),(5,10,7,12),word2vec映射后的词向量就是(5,6,7,8)。
隐藏层→输出层:为了避免要计算所有词的softmax概率,word2vec采样了霍夫曼树来代替从隐藏层到输出softmax层的映射。
在这里插入图片描述
对于上图所示的霍夫曼树,霍夫曼树的内部节点类似之前神经网络中隐藏层的神经元,根节点的词向量对应我们求和平均后的词向量,叶子节点对应softmax输出层神经元,在霍夫曼树中,隐藏层到输出层的映射是沿着霍夫曼树一步一步完成,所以这种softmax取名为:Hierarchical Softmax(层次softmax)。
针对霍夫曼树,采用二元逻辑回归的方法,即沿着左子树走就是负类(霍夫曼编码为1),沿着右子树走就是正类(霍夫曼编码为0),判别正负类采用sigmoid函数,即:
P ( + ) = 1 1 + e − x w T θ P(+)=\frac{1}{1+e^{-x_w^T\theta}} P(+)=1+exwTθ1
其中 x w x_w xw是当前内部节点的词向量, θ \theta θ是逻辑回归中模型参数。

霍夫曼树的好处:首先,由于是二叉树,之前计算量为 V V V,现在变成了 log ⁡ 2 V \log_2V log2V。第二,由于使用霍夫曼树是高频的词靠近树根,这样高频词需要更少的时间会被找到,这符合我们的贪心优化思想。

2.3.1 基于Hierarchical Softmax的模型梯度计算

我们采用最大似然法寻找所有节点的词向量和参数 θ \theta θ,若输出层最大的softmax概率为词 w 2 w_2 w2,则期望最大化函数为:
∏ i = 1 3 P ( n ( w 2 , i ) ) = ( 1 − 1 1 + e − x w T θ 1 ) ( 1 − 1 1 + e − x w T θ 2 ) 1 1 + e − x w T θ 3 \prod_{i=1}^3P(n(w_2, i))=(1-\frac{1}{1+e^{-x_w^T\theta_1}})(1-\frac{1}{1+e^{-x_w^T\theta_2}})\frac{1}{1+e^{-x_w^T\theta_3}} i=13P(n(w2,i))=(11+exwTθ11)(11+exwTθ21)1+exwTθ31

更为一般的描述:定义输入的词为 w w w,输入层到隐藏层求和平均后的词向量为 x w x_w xw,即为霍夫曼树根节点的词向量,从根节点到 w w w所在的叶子节点,包含的节点总数为 l w l_w lw w w w在霍夫曼树中从根节点开始,经过的第 i i i个节点表示为 P i w P_i^w Piw,对应的霍夫曼编码为 d i w d_i^w diw,其中 i = 2 , 3 , . . . , l w i=2,3,...,l_w i=2,3,...,lw,该节点对应的模型参数为 θ i w \theta_i^w θiw,其中 i = 1 , 2 , . . . , l w − 1 i=1,2,...,l_w-1 i=1,2,...,lw1,没有 i = l w i=l_w i=lw是因为模型参数仅仅针对霍夫曼树的内部节点。
定义 w w w经过霍夫曼树某一个节点 j j j的逻辑回归概率为 P ( d j w ∣ x w , θ j − 1 w ) P(d_j^w|x_w, \theta_{j-1}^w) P(djwxw,θj1w),其表达式为:
P ( d j w ∣ x w , θ j − 1 w ) = { σ ( x w T θ j − 1 w ) , d j w = 0 1 − σ ( x w T θ j − 1 w ) , d j w = 1 P(d_j^w|x_w, \theta_{j-1}^w)= \begin{cases} \sigma (x_w^T\theta_{j-1}^w), & d_j^w=0 \\ 1- \sigma (x_w^T\theta_{j-1}^w), & d_j^w=1 \\ \end{cases} P(djwxw,θj1w)={σ(xwTθj1w),1σ(xwTθj1w),djw=0djw=1
对于一个目标输出次 w w w,其输出概率函数为:
∏ j = 2 l w P ( d j w ∣ x w , θ j − 1 w ) = ∏ j = 2 l w [ σ ( x w T θ j − 1 w ) ] 1 − d j w [ 1 − σ ( x w T θ j − 1 w ) ] d j w \prod_{j=2}^{l_w} P(d_j^w|x_w, \theta_{j-1}^w)=\prod_{j=2}^{l_w}[\sigma(x_w^T\theta_{j-1}^w)]^{1-d_j^w}[1-\sigma(x_w^T\theta_{j-1}^w)]^{d_j^w} j=2lwP(djwxw,θj1w)=j=2lw[σ(xwTθj1w)]1djw[1σ(xwTθj1w)]djw

在word2vec中,由于使用的是随机梯度上升法(一般采用梯度下降法求解损失函数的最小值,但这里是求解概率函数的最大值,所以采用梯度上升法,所以并没有把所有样本的似然乘起来得到真正的训练集最大似然,仅仅每次只用一个样本更新梯度,这样做的目的是减少梯度计算量。所以对应的对数似然函数 L L L为:
L = l o g ∏ j = 2 l w P ( d j w ∣ x w , θ j − 1 w ) = ∑ j = 2 l w ( ( 1 − d j w ) l o g [ σ ( x w T θ j − 1 w ) ] + d j w l o g [ 1 − σ ( x w T θ j − 1 w ) ] ) L=log\prod_{j=2}^{l_w}P(d_j^w|x_w, \theta_{j-1}^w)=\sum_{j=2}^{l_w}((1-d_j^w)log[\sigma(x_w^T\theta_{j-1}^w)]+d_j^wlog[1-\sigma(x_w^T\theta_{j-1}^w)]) L=logj=2lwP(djwxw,θj1w)=j=2lw((1djw)log[σ(xwTθj1w)]+djwlog[1σ(xwTθj1w)])

对数似然函数 L L L对参数 θ j − 1 w \theta_{j-1}^{w} θj1w的梯度为:
∂ L ∂ θ j − 1 w = ( 1 − d j w ) σ ( x w T θ j − 1 w ) ( 1 − σ ( x w T θ j − 1 w ) σ ( x w T θ j − 1 w ) x w − d j w σ ( x w T θ j − 1 w ) ( 1 − σ ( x w T θ j − 1 w ) ) 1 − σ ( x w T θ j − 1 w ) x w = ( 1 − d j w ) ( 1 − σ ( x w T θ j − 1 w ) x w − d j w σ ( x w T θ j − 1 w ) x w = ( 1 − d j w − σ ( x w T θ j − 1 w ) x w \frac{\partial L}{\partial \theta_{j-1}^w} = (1-d_j^w)\frac{\sigma(x_w^T\theta_{j-1}^w)(1-\sigma(x_w^T\theta_{j-1}^w)}{\sigma(x_w^T\theta_{j-1}^w)}x_w - d_j^w \frac{\sigma(x_w^T\theta_{j-1}^w)(1-\sigma(x_w^T\theta_{j-1}^w))}{1-\sigma(x_w^T\theta_{j-1}^w)}x_w \\ = (1-d_j^w)(1-\sigma(x_w^T\theta_{j-1}^w)x_w-d_j^w\sigma(x_w^T\theta_{j-1}^w)x_w \\ =(1-d_j^w-\sigma(x_w^T\theta_{j-1}^w)x_w θj1wL=(1djw)σ(xwTθj1w)σ(xwTθj1w)(1σ(xwTθj1w)xwdjw1σ(xwTθj1w)σ(xwTθj1w)(1σ(xwTθj1w))xw=(1djw)(1σ(xwTθj1w)xwdjwσ(xwTθj1w)xw=(1djwσ(xwTθj1w)xw
采用同样的方式,对 x w x_w xw的梯度为:
∂ L ∂ x w = ∑ j = 2 l w ( 1 − d j w − σ ( x w T θ j − 1 w ) ) θ j − 1 w \frac{\partial L}{\partial x_w}=\sum_{j=2}^{l_w}(1-d_j^w-\sigma(x_w^T\theta_{j-1}^w))\theta_{j-1}^w xwL=j=2lw(1djwσ(xwTθj1w))θj1w

2.3.2 基于Hierarchical Softmax的CBOW模型

定义词向量的维度为 M M M,以及CBOW的上下文大小为2c,对于训练样本中的每一个词,其前面和后面各c个词作为CBOW的输入,该词本身 w w w为样本的输出,期望softmax概率最大。
在做CBOW前,先用词汇表建立一颗霍夫曼树。

  • 第一步:对于输入层到隐藏层的映射,即对词 w w w周围的2c个词向量求和取平均,如下所示:
    x w = 1 2 c ∑ i = 1 2 c x i x_w=\frac{1}{2c}\sum_{i=1}^{2c}x_i xw=2c1i=12cxi
  • 第二步:采用梯度上升法更新 θ j − 1 w \theta_{j-1}^w θj1w x w x_w xw,注意这里 x w x_w xw采用2c个词向量相加而成,所以我们梯度更新完后直接用梯度更新各个 x i , i = 1 , 2 , . . . , 2 c x_i, i=1,2,...,2c xi,i=1,2,...,2c,即:
    θ j − 1 w = θ j − 1 w + η ( 1 − d j w − σ ( x w T θ j − 1 w ) x w x i = x i + η ( 1 − d j w − σ ( x w T θ j − 1 w ) θ j − 1 w , ( i = 1 , 2 , . . . , 2 c ) \theta_{j-1}^w=\theta_{j-1}^w+\eta(1-d_j^w-\sigma(x_w^T\theta_{j-1}^w)x_w \\ x_i=x_i+\eta(1-d_j^w-\sigma(x_w^T\theta_{j-1}^w)\theta_{j-1}^w, (i=1,2,...,2c) θj1w=θj1w+η(1djwσ(xwTθj1w)xwxi=xi+η(1djwσ(xwTθj1w)θj1w,(i=1,2,...,2c)
    其中 η \eta η为梯度上升法中的步长。

总结: 基于Hierarchical Softmax的CBOW模型算法流程

  • 输入:基于CBOW的语料训练样本,词向量的维度大小 M M M,CBOW的上下文大小2c,步长 η \eta η
  • 输出:霍夫曼树的内部节点模型参数 θ \theta θ,所有的词向量 w w w
  • 1)基于语料训练样本建立霍夫曼树。
  • 2)随机初始化所有的模型参数 θ \theta θ,所有的词向量 w w w
  • 3)进行梯度上升迭代过程,对于训练集中的每一个样本 ( c o n t e x t ( w ) (context(w) (context(w) w w w)做如下处理:
          a) e = 0 e=0 e=0, 计算 x w = 1 2 c ∑ i = 1 2 c x i x_w=\frac{1}{2c}\sum_{i=1}^{2c}x_i xw=2c1i=12cxi
          b) for j j j = 2 to l w l_w lw, 计算:
                f = θ ( x w T θ j − 1 w ) f=\theta(x^T_wθ^w_{j−1}) f=θ(xwTθj1w)
                g = ( 1 − d j w − f ) η g=(1-d_j^w-f)\eta g=(1djwf)η
                e = e + g θ j − 1 w e=e+g\theta_{j-1}^w e=e+gθj1w
                θ j − 1 w = θ j − 1 w + g x w \theta_{j-1}^w=\theta_{j-1}^w+gx_w θj1w=θj1w+gxw
          c) 对于 c o n t e x t ( w ) context(w) context(w)中的每一个词向量 x i x_i xi(共2c个)进行更新:
                x i = x i + e x_i=x_i+e xi=xi+e
          d) 如果梯度收敛,则结束梯度迭代,否则回到步骤3继续迭代。

2.3.3 基于Hierarchical Softmax的Skip-Gram模型

对于训练样本中的每一个词,该词本身作为样本的输入,其前面 c c c个词和后面的 c c c个词作为Skip-Gram的输出,期望这些词的softmax概率最大。

  • 第一步:输入层到隐藏层:由于只有一个词,所以 x w x_w xw就是 w w w对应的词向量。
  • 第二步:通过梯度上升法更新 θ j − 1 w \theta_{j-1}^w θj1w x w x_w xw,由于 x w x_w xw周围有 2 c 2c 2c个词向量,所以我们希望 P ( x i ∣ x w ) , i = 1 , 2 , . . . , 2 c P(x_i|x_w), i=1,2,...,2c P(xixw),i=1,2,...,2c最大,同时希望概率 P ( x w ∣ x i ) , i = 1 , 2 , . . . , 2 c P(x_w|x_i), i=1,2,...,2c P(xwxi),i=1,2,...,2c最大。那么是使用 P ( x i ∣ x w ) P(x_i|x_w) P(xixw)还是 P ( x w ∣ x i ) P(x_w|x_i) P(xwxi)呢?word2vec使用了 P ( x w ∣ x i ) P(x_w|x_i) P(xwxi)。这样的话,在一个迭代窗口中,我们不是只更新 x w x_w xw一个词,而是 x i x_i xi 2 c 2c 2c个词。

总结: 基于Hierarchical Softmax的Skip-Gram模型算法流程

  • 输入:基于Skip-Gram的语料训练样本,词向量的维度大小 M M M,Skip-Gram的上下文大小2c,步长 η \eta η
  • 输出:霍夫曼树的内部节点模型参数 θ \theta θ,所有的词向量 w w w
  • 1)基于语料训练样本建立霍夫曼树。
  • 2)随机初始化所有的模型参数 θ \theta θ,所有的词向量 w w w
  • 3)进行梯度上升迭代过程,对于训练集中的每一个样本 ( ( (w , c o n t e x t ( w ) ,context(w) context(w))做如下处理:
          a) for i i i = 1 to 2 c 2c 2c:
             i) e = 0 e=0 e=0
             ii) for j j j = 2 to l w l_w lw, 计算:
                  f = θ ( x w T θ j − 1 w ) f=\theta(x^T_wθ^w_{j−1}) f=θ(xwTθj1w)
                  g = ( 1 − d j w − f ) η g=(1-d_j^w-f)\eta g=(1djwf)η
                  e = e + g θ j − 1 w e=e+g\theta_{j-1}^w e=e+gθj1w
                  θ j − 1 w = θ j − 1 w + g x i \theta_{j-1}^w=\theta_{j-1}^w+gx_i θj1w=θj1w+gxi
             iii)计算:
                  x i = x i + e x_i=x_i+e xi=xi+e
          b) 如果梯度收敛,则结束梯度迭代,否则回到步骤a继续迭代。

2.3.4 Hierarchical Softmax的缺点与改进

缺点:
使用霍夫曼树来代替传统的神经网络,可以提高模型训练的效率。但是如果我们的训练样本里的中心词 w w w是一个很生僻的词,那么就得在霍夫曼树中辛苦的向下走很久了。能不能不用搞这么复杂的一颗霍夫曼树,将模型变的更加简单呢?
改进:
Negative Sampling就是这么一种求解word2vec模型的方法,它摒弃了霍夫曼树,采用了Negative Sampling(负采样)的方法来求解。

2.4 基于Negative Sampling的模型概述

Negative Sampling(负采样):中心词 w w w的上下文共有 2 c 2c 2c个词,记为 c o n t e x t ( w ) context(w) context(w),由于中心词 w w w和上下文 c o n t e x t ( w ) context(w) context(w)是相关存在的,因此这是一个真实的正类,通过Negative Sampling采样,得到 n e g neg neg个和 w w w不同的中心词 w i , i = 1 , 2 , . . . , n e g w_i, i=1,2,...,neg wi,i=1,2,...,neg,这样词 w i w_i wi c o n t e x t ( w ) context(w) context(w)组成了真实不存在的负类。利用一个正类和 n e g neg neg个负类,采用logistics回归,得到负采样对应的每个词 w i w_i wi对应的模型参数 θ i \theta_i θi和每个词的词向量。

从上面的描述可以看出,Negative Sampling由于没有采用霍夫曼树,每次只是通过采样 n e g neg neg个不同的中心词做负例,就可以训练模型,因此整个过程要比Hierarchical Softmax简单。

有两个问题还需要弄明白:1)如何通过一个正例和neg个负例进行二元逻辑回归呢? 2) 如何进行负采样呢?

2.4.1 基于Negative Sampling的模型梯度计算

在逻辑回归中,我们定义正类的词向量为 w 0 w_0 w0 n e g neg neg个负类为 ( c o n t e x t ( w ) , w i ) , i = 1 , 2 , . . . , n e g (context(w), w_i), i=1,2,...,neg (context(w),wi),i=1,2,...,neg
在逻辑回归中,正类的概率为:
P ( c o n t e x t ( w 0 ) , w i ) = σ ( x w 0 T θ w i ) , y i = 1 , i = 0 P(context(w_0), w_i)=\sigma(x^T_{w_0}\theta^{w_i}), y_i=1, i=0 P(context(w0),wi)=σ(xw0Tθwi),yi=1,i=0
负类概率为:
P ( c o n t e x t ( w 0 ) , w i ) = 1 − σ ( x w 0 T θ w i ) , y i = 0 , i = 1 , 2 , . . . , n e g P(context(w_0), w_i)=1-\sigma(x^T_{w_0}\theta^{w_i}), y_i=0, i=1,2,...,neg P(context(w0),wi)=1σ(xw0Tθwi),yi=0,i=1,2,...,neg
最大化目标为:
[ σ ( x w 0 T θ w i ) ] ∏ i = 1 n e g [ 1 − σ ( x w 0 T θ w i ) ] [\sigma(x^T_{w_0}\theta^{w_i})]\prod_{i=1}^{neg}[1-\sigma(x^T_{w_0}\theta^{w_i})] [σ(xw0Tθwi)]i=1neg[1σ(xw0Tθwi)]
最大化似然函数为:
∏ i = 0 n e g P ( c o n t e x t ( w 0 ) , w i ) = [ σ ( x w 0 T θ w i ) ] y i ∏ i = 1 n e g [ 1 − σ ( x w 0 T θ w i ) ] 1 − y i = ∏ i = 0 n e g [ σ ( x w 0 T θ w i ) ] y i [ 1 − σ ( x w 0 T θ w i ) ] 1 − y i \prod_{i=0}^{neg}P(context(w_0), w_i)=[\sigma(x^T_{w_0}\theta^{w_i})]^{y_i}\prod_{i=1}^{neg}[1-\sigma(x^T_{w_0}\theta^{w_i})]^{1-y_i} \\ =\prod_{i=0}^{neg}[\sigma(x^T_{w_0}\theta^{w_i})]^{y_i}[1-\sigma(x^T_{w_0}\theta^{w_i})]^{1-y_i} i=0negP(context(w0),wi)=[σ(xw0Tθwi)]yii=1neg[1σ(xw0Tθwi)]1yi=i=0neg[σ(xw0Tθwi)]yi[1σ(xw0Tθwi)]1yi
对数似然函数为:
L = ∑ i = 0 n e g [ y i l o g ( σ ( x w 0 T θ w i ) ) + ( 1 − y i ) l o g ( 1 − σ ( x w 0 T θ w i ) ) ] L=\sum_{i=0}^{neg}[y_i log(\sigma(x_{w_0}^T\theta ^{w_i}))+(1-y_i)log(1-\sigma(x_{w_0}^T\theta ^{w_i}))] L=i=0neg[yilog(σ(xw0Tθwi))+(1yi)log(1σ(xw0Tθwi))]
和Hierarchical Softmax类似,我们采用随机梯度上升法,仅仅每次只用一个样本更新梯度,来进行迭代更新得到我们需要的 x w i x_{w_i} xwi θ w i , i = 0 , 1 , . . n e g \theta^{w_i}, i=0,1,..neg θwi,i=0,1,..neg, 所以要求出他们的梯度。
先求 θ w i \theta^{w_i} θwi的梯度为:
∂ L ∂ θ w i = ( y i − σ ( x w 0 T θ w i ) ) x w 0 \frac{\partial L}{\partial \theta^{w_i}}=(y_i-\sigma(x_{w_0}^T\theta ^{w_i}))x_{w_0} θwiL=(yiσ(xw0Tθwi))xw0
同样的方法,求出 x w 0 x_{w_0} xw0的梯度如下:
∂ L ∂ x w 0 = ∑ i = 0 n e g ( y i − σ ( x w 0 T θ w i ) ) θ w i \frac{\partial L}{\partial x^{w_0}}=\sum_{i=0}^{neg}(y_i-\sigma(x_{w_0}^T\theta ^{w_i}))\theta^{w_i} xw0L=i=0neg(yiσ(xw0Tθwi))θwi
采用梯度上升法对参数进行更新。

2.4.2 Negative Sampling负采样方法

对于负采样 n e g neg neg个样本,我们假设词汇表大小为 V V V,将长度为1的线段分成 V V V份,每份对应词汇表中的一个词,这样的话高频词对应的线段长,低频词对应的线段短,每个词 w w w的线段长度由下式确定:
l e n ( w ) = c o u n t ( w ) ∑ u ∈ v o c a b c o u n t ( u ) len(w)=\frac{count(w)}{\sum_{u\in vocab}count(u)} len(w)=uvocabcount(u)count(w)
在word2vec中,分子分母都取3/4次幂,由下式确定:
l e n ( w ) = ( c o u n t ( w ) ) 3 / 4 ∑ u ∈ v o c a b ( c o u n t ( u ) ) 3 / 4 len(w)=\frac{(count(w))^{3/4}}{\sum_{u\in vocab}(count(u))^{3/4}} len(w)=uvocab(count(u))3/4(count(w))3/4
在采样前,我们先将长度为1的线段等分成M份(word2vec中M默认取 1 0 8 10^8 108),其中M>>V,这样可以保证每个词对应的线段都会划分成对应的小段,而M份中的每一份都会落在某个词对应的线段上。在采样的时候,我们需要从M个位置中采样出 n e g neg neg个位置就行,此时采样得到的每一个位置对应到的线段所属的词就是我们的负类词。
在这里插入图片描述

2.4.3 基于Negative Sampling的CBOW模型

总结: 基于Negative Sampling的CBOW模型算法流程

  • 输入:基于CBOW的语料训练样本,词向量的维度大小M count,CBOW的上下文大小 2 c 2c 2c,步长 η \eta η, 负采样的个数 n e g neg neg
  • 输出:词汇表每个词对应的模型参数 θ \theta θ,所有的词向量 x w x_w xw
    1)初始化所有模型参数 θ \theta θ和词向量 w w w
    2)对于每个训练样本 ( c o n t e x t ( w 0 ) , w 0 ) (context(w_0), w_0) (context(w0),w0),负采样出 n e g neg neg个负类词 w i , i = 1 , 2 , . . . , n e g w_i, i=1,2,...,neg wi,i=1,2,...,neg
    3)进行梯度上升迭代过程,对于训练集中的每一个样本 ( c o n t e x t ( w 0 ) , w 0 , w 1 , w 2 , . . . , w n e g ) (context(w_0), w_0, w_1, w_2,...,w_{neg}) (context(w0),w0,w1,w2,...,wneg)做如下处理:
          a)e=0, 计算 x w 0 = 1 2 c ∑ i = 1 2 c x i x_{w_0}=\frac{1}{2c}\sum_{i=1}^{2c}x_i xw0=2c1i=12cxi
          b)for i=0 to neg, 计算:            
                f = σ ( x w 0 T θ w i ) f=\sigma(x_{w_0}^T\theta^{w_i}) f=σ(xw0Tθwi)
                g = ( y i − f ) η g=(y_i-f)\eta g=(yif)η
                e = e + g θ w i e=e+g\theta^{w_i} e=e+gθwi
                θ w i = θ w i + g x w 0 \theta^{w_i}=\theta^{w_i}+gx^{w_0} θwi=θwi+gxw0
          c)对于 c o n t e x t ( w ) context(w) context(w)中得每一个词向量 x k x_k xk(共 2 c 2c 2c个)进行更新:
                x k = x k + e x_k=x_k+e xk=xk+e
          d)如果梯度收敛,则接数梯度迭代,否则回到步骤3继续迭代。

2.4.4 基于Negative Sampling的Skip-Gram模型

总结: 基于Negative Sampling的Skip-Gram模型算法流程

  • 输入:基于Skip-Gram的语料训练样本,词向量的维度大小M count,Skip-Gram的上下文大小 2 c 2c 2c,步长 η \eta η,负采样的个数 n e g neg neg
  • 输出:词汇表每个词对应的模型参数 θ \theta θ,所有的词向量 x w x_w xw
    1)初始化所有模型参数 θ \theta θ和词向量 w w w
    2)对于每个训练样本 ( c o n t e x t ( w 0 ) , w 0 ) (context(w_0), w_0) (context(w0),w0),负采样出 n e g neg neg个负类词 w i , i = 1 , 2 , . . . , n e g w_i, i=1,2,...,neg wi,i=1,2,...,neg
    3)进行梯度上升迭代过程,对于训练集中的每一个样本 ( c o n t e x t ( w 0 ) , w 0 , w 1 , w 2 , . . . , w n e g ) (context(w_0), w_0, w_1, w_2,...,w_{neg}) (context(w0),w0,w1,w2,...,wneg)做如下处理:
          a)for i=1 to 2c:
                i)e=0
                ii)for j=0 to neg,计算:
                     f = σ ( x w 0 i T θ w j ) f=\sigma(x_{w_{0_i}}^T\theta^{w_j}) f=σ(xw0iTθwj)
                     g = ( y j − f ) η g=(y_j-f)\eta g=(yjf)η
                     e = e + g θ w j e=e+g\theta^{w_j} e=e+gθwj
                     θ w j = θ w j + g x w 0 i \theta^{w_j}=\theta^{w_j}+gx^{w_{0_i}} θwj=θwj+gxw0i                
                iii)更新词向量:
                     x w 0 i = x w 0 i + e x_{w_{0_i}}=x_{w_{0_i}}+e xw0i=xw0i+e  
          b)如果梯度收敛,则接数梯度迭代,否则回到步骤a继续迭代。

3、基于gensim库的word2vec实践

3.1 Word2Vec函数参数说明

from gensim.models import Word2Vec
Word2Vec(sentences=None, corpus_file=None, size=100, alpha=0.025, window=5, 
min_count=5, max_vocab_size=None, sample=0.001, seed=1, workers=3, min_alpha=0.0001, sg=0, hs=0, 
negative=5, ns_exponent=0.75, cbow_mean=1, hashfxn=<built-in function hash>, iter=5, null_word=0, trim_rule=None, 
sorted_vocab=1, batch_words=10000, compute_loss=False, callbacks=(), max_final_vocab=None)

参数说明:

  • sentences (iterable of iterables, optional) – 供训练的句子,可以使用简单的列表,但是对于大语料库,建议直接从磁盘/网络流迭代传输句子。参阅word2vec模块中的BrownCorpus,Text8Corpus或LineSentence。
  • corpus_file (str, optional) – LineSentence格式的语料库文件路径。
  • size (int, optional) – 词汇映射到的N维空间的维度数量
  • window (int, optional) – 一个句子中当前单词和被预测单词的最大距离。
  • min_count (int, optional) – 用于修剪内部词典,忽略词频小于此值的单词。
  • workers (int, optional) – 训练模型时使用的线程数。
  • sg ({0, 1}, optional) – 模型的训练算法: 1: skip-gram; 0: CBOW.
  • hs ({0, 1}, optional) – 1: 采用hierarchical softmax训练模型; 0: 使用negative sample负采样。
  • negative (int, optional) – > 0: 使用负采样,设置多个负采样(通常在5-20之间)。
  • ns_exponent (float, optional) – 负采样分布指数。1.0样本值与频率成正比,0.0样本所有单词均等,负值更多地采样低频词。
  • cbow_mean ({0, 1}, optional) – 0: 使用上下文单词向量的总和; 1: 使用均值,适用于使用CBOW。
  • alpha (float, optional) – 初始学习率。
  • min_alpha (float, optional) – 随着训练的进行,学习率线性下降到min_alpha。
  • seed (int, optional) – 随机数发生器种子。
  • max_vocab_size (int, optional) – 词汇构建期间RAM的限制; 如果有更多的独特单词,则修剪不常见的单词。 每1000万个类型的字需要大约1GB的RAM。
  • max_final_vocab (int, optional) – 自动选择匹配的min_count将词汇限制为目标词汇大小。
  • sample (float, optional) – 高频词随机下采样的配置阈值,范围是(0,1e-5)。
  • hashfxn (function, optional) – 哈希函数用于随机初始化权重,以提高训练的可重复性。
  • iter (int, optional) – 迭代次数。
  • trim_rule (function, optional) – 词汇修剪规则,指定某些词语是否应保留在词汇表中,修剪掉或使用默认值处理。
  • sorted_vocab ({0, 1}, optional) – 如果为1,则在分配单词索引前按降序对词汇表进行排序。
  • batch_words (int, optional) – 每一个batch传递给线程单词的数量。
  • compute_loss (bool, optional) – 如果为True,则计算并存储可使用get_latest_training_loss()检索的损失值。
  • callbacks (iterable of CallbackAny2Vec, optional) – 在训练中特定阶段执行回调序列。

3.2 Word2Vec实践

基于gensim库的word2vec需要一系列的句子作为输入,其中每个语句都是一个词汇列表(经过分词处理):

3.2.1 英文文本预处理

  • 小写化
    使用python内置的字符串.lower()函数进行转换。
  • 词干提取
    当遇到两个或两个以上单词具有共同根源的情况。 例如,agreed, agreeing 和 agreeable这三个词具有相同的词根。 涉及任何这些词的搜索应该把它们当作是根词的同一个词。所以需要进行词干提取。在NLTK库中有一些方法来完成这个链接,并给出显示根词的输出。 以下程序使用Porter Stemming算法进行词干提取。
  • 词形还原
    简单说来,词形还原就是去掉单词的词缀,提取单词的主干部分,通常提取后的词汇会是字典中的单词,不同于词干提取(stemming),提取后的单词不一定会出现在词汇中。比如,单词“cups”词形还原后的单词为“cup”,单词“ate”词形还原后的单词为“eat”。在下面的程序中,使用WordNet词法数据库进行词形化。
#导入所需的库
from gensim.models import Word2Vec
from nltk.stem import WordNetLemmatizer #词形还原
from nltk.stem.porter import PorterStemmer #词干提取
import logging # 导入模块并设置日志记录
from smart_open import smart_open
import os
import jieba
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
import nltk
nltk.download('wordnet') #初次运行nltk时,需要执行此行,否则会报错
sentences = [  
'2018年10月份,麻省理工学院的Zakaria el Hjouji, D. Scott Hunter等学者发表了《The Impact of Bots on Opinions in Social Networks》,',
'该研究通过分析 Twitter 上的机器人在舆论事件中的表现,证实了社交网络机器人可以对社交网络舆论产生很大的影响,不到消费者总数1%的活跃机器人,就可能左右整个舆论风向。',
'麻省理工学院研究组的这项工作,最大的发现是,影响社交网络舆论所需要的机器人,其实是很少的。少数活跃的机器人,可以对网络舆论产生重大影响。',
'机器人检测算法,会判断某用户是机器人的概率,但实际操作中研究者发现,该算法把几个经常转发但不常被@ 的真实用户也当做了机器人。所以研究者对有实名认证的 Twitter 用户做了筛查,把他们都归为真实用户。',
'不论是真实的推特用户还是推特机器人,它们的三个基本操作是,关注、转发和评论(类似微博)。通过跟踪这些互动,研究者可以有效量化 Twitter 账号的行为。',
'直觉上,那些不太关注别人的用户,也不太可能关注你。而且社交圈子重叠很重要,如果 A 和 B 是好友,那么关注 A 的用户就有较大概率关注 B。',
'虽然人们在收到新信息时会更新他们的观点,但这个过程会随着时间的推移而减弱,他们的观点会逐渐变得顽固。Zaman 认为,如果你已经掌握了很多信息,你就越来越难听从别人的观点,新说法不会改变你的看法。',
'该研究团队基于过往研究,给出了网络舆论模型的核心假设:',
'社交网络中的个人是基于其朋友推文中的观点,来更新自身的观点;',
'网络中某些用户的观点是顽固的,其观点不会轻易改变,而且顽固用户会推动其他用户(摇摆不定的中间派)改变观点。',
'虽然社交媒体机器人不会带来物理威胁,但它们却可能有力影响到网络舆论。在微博里,各类水军已经经常出现在营销造势、危机公关中。虽然你能一眼识别出谁是水军,但仍然可能不知不觉地被他们影响。',
'这些机器人看似僵尸,发起声来,比人类响亮得多,可能只要几十个几百个就足够扭转舆论!',
'所以,从社会化媒体数据挖掘的角度来看,信息的真实性并不重要,只要文章、帖子或者评论能影响到浏览者或受众,具有一定的(潜在)影响力,这类社媒数据数据就值得去挖掘。',
'更进一步说,跟销售数据反映消费者决策价值、搜索数据反映消费者意图价值相比,虽然社会化媒体文本数据的价值密度最低,好比是蕴藏金子和硅、却提炼极为困难的沙子,但由于它在互联网领域的分布极为广泛,',
'且蕴含着对客观世界的细节描述和主观世界的宣泄(情绪、动机、心理等),其最大价值在于潜移默化地操控人的思想和行为的影响力,',
'通过社会化媒体挖掘,我们可以得到对目标受众具有(潜在)影响力的商业情报。淘沙得金,排沙简金,最终得到的分析结果用以预判受众的思考和行为,为我们的生产实践服务。'
          ]
porter_stemmer=PorterStemmer() #词干提取
wordnet_lemmatizer=WordNetLemmatizer() #词形还原
sentences = [wordnet_lemmatizer.lemmatize(porter_stemmer.stem(i.lower())) for i  in sentences]
sentences[:2]
#结果
['2018年10月份,麻省理工学院的zakaria el hjouji, d. scott hunter等学者发表了《the impact of bots on opinions in social networks》,',
 '该研究通过分析 twitter 上的机器人在舆论事件中的表现,证实了社交网络机器人可以对社交网络舆论产生很大的影响,不到消费者总数1%的活跃机器人,就可能左右整个舆论风向。']
data_cut = [jieba.lcut(i) for i  in sentences] #对语句进行分词
jieba.add_word('2018年10月份')#将词加入到切词文本中,避免被切分
jieba.add_word('社交网络')#将词加入到切词文本中,避免被切分
data_cut = [' '.join(jieba.lcut(i)) for i  in sentences] #用空格隔开词汇,形成字符串,便于后续的处理
stoplist = [i.strip() for i in open('./stop.txt',encoding='utf-8').readlines()]  #载入停用词列表
sentences = [[word for word in document.strip().split() if word not in stoplist] for document in data_cut]   #过滤语句中的停用词
sentences[:3]  #展示预处理后语句列表中的3个样例

在这里插入图片描述

3.2.2 Word2Vec模型构建

#构建模型
model=Word2Vec(sentences, min_count=1, vector_size=100, window=5, sg=0, hs=0)

日志如下所示:
在这里插入图片描述
这里我们调用Word2Vec创建模型实际上会对数据执行两次迭代操作;
第一轮操作会统计词频来构建内部的词典数结构;
第二轮操作会进行神经网络训练,而这两个步骤是可以分步进行的。

#分步训练模型
model2=gensim.models.Word2Vec(min_count=1) #一个空模型
model2.build_vocab(sentences)
model2.train(sentences, total_examples=model2.corpus_count, epochs=model2.epochs)

日志及输出如下所示:
在这里插入图片描述
上述结果表明:模型处理了1480个原始词汇,其中包含大量的重复词汇;其中有903个有效词汇,即不重复的词汇。

#打印模型
print(model2)
#打印词汇列表
print(model2.wv.index_to_key) #获得所有的词汇
#查看词向量的维度
print(model2.wv.vectors.shape)

结果:
Word2Vec(vocab=195, vector_size=100, alpha=0.025)
[‘机器人’, ‘用户’, ‘舆论’, ‘观点’, ‘影响’, ‘关注’, ‘中’, ‘数据’, ‘价值’, ‘媒体’, ‘社交网络’, ‘网络’, ‘消费者’, ‘研究’, ‘影响力’, ‘研究者’, ‘社会化’, ‘真实’, ‘twitter’, ‘受众’, ‘顽固’, ‘信息’, ‘改变’, ‘a’, ‘概率’, ‘挖掘’, ‘发现’, ‘世界’, ‘潜在’, ‘更新’, ‘水军’, ‘活跃’, ‘评论’, ‘算法’, ‘转发’, ‘新’, ‘麻省理工学院’, ‘推特’, ‘b’, ‘分析’, ‘微博’, ‘减弱’, ‘基本操作’, ‘类似’, ‘三个’, ‘推移’, ‘变得’, ‘跟踪’, ‘时间’, ‘过程’, ‘互动’, ‘量化’, ‘账号’, ‘直觉’, ‘时会’, ‘不太’, ‘筛查’, ‘不太可能’, ‘社交圈子’, ‘重叠’, ‘收到’, ‘较大’, ‘好友’, ‘不论是’, ‘服务’, ‘做’, ‘the’, ‘social’, ‘in’, ‘opinions’, ‘on’, ‘bots’, ‘of’, ‘impact’, ‘发表’, ‘认证’, ‘学者’, ‘hunter’, ‘scott’, ‘d’, ‘hjouji’, ‘el’, ‘zakaria’, ‘networks’, ‘事件’, ‘表现’, ‘证实’, ‘实名’, ‘当做’, ‘几个’, ‘实际操作’, ‘判断’, ‘越来越’, ‘检测’, ‘工作’, ‘这项’, ‘研究组’, ‘风向’, ‘1%’, ‘总数’, ‘不到’, ‘很大’, ‘zaman’, ‘过往’, ‘难听’, ‘分布’, ‘互联网’, ‘沙子’, ‘困难’, ‘提炼’, ‘硅’, ‘金子’, ‘蕴藏’, ‘好比’, ‘最低’, ‘密度’, ‘文本’, ‘相比’, ‘意图’, ‘搜索’, ‘决策’, ‘销售’, ‘说’, ‘值得’, ‘社媒’, ‘领域’, ‘蕴含着’, ‘浏览者’, ‘客观’, ‘思考’, ‘预判’, ‘用以’, ‘最终’, ‘排沙简金’, ‘淘沙得金’, ‘情报’, ‘商业’, ‘目标’, ‘思想’, ‘操控’, ‘潜移默化’, ‘心理’, ‘动机’, ‘情绪’, ‘宣泄’, ‘主观’, ‘描述’, ‘细节’, ‘这类’, ‘帖子’, ‘说法’, ‘各类’, ‘微’, ‘威胁’, ‘物理’, ‘带来’, ‘社交’, ‘中间派’, ‘摇摆不定’, ‘推动’, ‘轻易’, ‘文中’, ‘推’, ‘朋友’, ‘假设’, ‘核心’, ‘模型’, ‘给出’, ‘生产实践’, ‘团队’, ‘看法’, ‘博里’, ‘经常出现’, ‘文章’, ‘营销’, ‘真实性’, ‘角度’, ‘数据挖掘’, ‘扭转’, ‘足够’, ‘几百个’, ‘几十个’, ‘响亮’, ‘人类’, ‘声来’, ‘发起’, ‘僵尸’, ‘看似’, ‘地被’, ‘识别’, ‘一眼’, ‘公关’, ‘危机’, ‘造势’, ‘2018年10月份’]
(195, 100)

#输出sentences中任意词的词向量
model.wv['社交网络']

输出是一个100为的词向量,array形式的:

array([ 7.0638563e-03, -1.5453972e-03, 7.9561304e-03, -9.4926925e-03,
-8.0229584e-03, -6.6784974e-03, -3.9848266e-03, 5.0417646e-03,
-3.8395165e-03, -8.3202971e-03, 8.4153796e-03, -3.7766348e-03,
8.6216880e-03, -4.8963465e-03, 3.9246543e-03, 4.9204812e-03,
2.4018991e-03, -2.8553701e-03, 2.8457786e-03, -8.3096121e-03,
-2.7729075e-03, -2.5885140e-03, 7.2201905e-03, -3.4714593e-03,
-6.6181072e-03, 4.3639163e-03, -4.7767439e-04, -3.6138245e-03,
6.8765590e-03, 3.8773620e-03, -3.8882059e-03, 7.8564388e-04,
9.1534043e-03, 7.7530909e-03, 6.3521513e-03, 4.7068754e-03,
2.4034036e-03, -1.8658022e-03, -6.3579832e-03, -3.5458809e-04,
-1.5626691e-03, -6.3265255e-04, -6.2650130e-03, 7.4525261e-03,
-6.5641920e-03, -7.2595710e-03, -2.7697689e-03, -1.4891585e-03,
-7.6317601e-03, 7.0505991e-04, -5.3201085e-03, -1.2653709e-03,
-7.3411190e-03, 1.9692294e-03, 3.2711832e-03, -1.6544895e-05,
-5.4436480e-03, -1.7203134e-03, 7.0711114e-03, 3.7382445e-03,
-8.8875266e-03, -3.3973909e-03, 2.3564966e-03, 2.1133679e-03,
-9.4995759e-03, 4.6018739e-03, -8.6265719e-03, -7.3342216e-03,
3.4420956e-03, -3.4228778e-03, 3.5506587e-03, 8.9171585e-03,
-3.5466484e-03, 9.3175955e-03, 1.7368469e-03, 9.8908665e-03,
5.6973854e-03, -9.1480138e-03, -3.3436336e-03, 6.5434463e-03,
5.6243753e-03, 8.7063080e-03, 6.8906588e-03, 8.0838138e-03,
-9.8373611e-03, 4.3032686e-03, -5.0042798e-03, 3.5393105e-03,
6.0869367e-03, 4.4086315e-03, 7.5518978e-03, 1.5278378e-03,
-1.2651186e-03, 5.8047809e-03, -5.5668419e-03, 5.7138383e-05,
9.4618490e-03, -5.5101938e-03, 3.8370828e-03, -8.1500122e-03],
dtype=float32)

#对文本sentences中任意一个词,找出与这个词最接近的10个词
model.wv.most_similar(['社交网络'], topn=10)
#结果
[('类似', 0.2692945897579193),
 ('值得', 0.23622459173202515),
 ('淘沙得金', 0.21686667203903198),
 ('密度', 0.21021078526973724),
 ('识别', 0.21017569303512573),
 ('思想', 0.20124150812625885),
 ('文章', 0.1793317049741745),
 ('搜索', 0.17790819704532623),
 ('危机', 0.162555530667305),
 ('发表', 0.15478317439556122)]

#找出与“社交网络”“舆论”最近,与“研究”最远的一个词
model.wv.most_similar(positive=['社交网络', '舆论'], negative=['研究'], topn=1)
#结果
[('值得', 0.2695724070072174)]

#计算两个词之间的相似性
model.wv.similarity('社交网络', '文章')
#结果
0.17933172

#找出不同类的词
model.wv.doesnt_match('社交网络 文章 研究 舆论'.split())
#结果
'舆论'

#模型保存与模型加载
model.save('word2vec.model')
model=Word2Vec.load('word2vec.model')
#对多个本地文档进行训练
import os
from nltk.stem import WordNetLemmatizer #词形还原
from nltk.stem.porter import PorterStemmer #词干提取
wordnet_lemmatizer=WordNetLemmatizer() #词形还原
porter_stemmer=PorterStemmer() #词干提取
stoplist = [i.strip() for i in open('./stop.txt',encoding='utf-8').readlines()]  #载入停用词列表
#对多个本地文档进行训练
class MySentence(object):
    def __init__(self, dirname):
        self.dirname=dirname
    def __iter__(self):
        for name in os.listdir(self.dirname):
            print('正在处理的文件:%s'%name)
            #smart_open是Python内置命令open()的嵌入式替代:open()能做的它都可以做,并外加了许多有效的功能。
            for line in smart_open(os.path.join(self.dirname, name), 'r', encoding='utf-8'): 
                line=line.lower() #小写化
                line=wordnet_lemmatizer.lemmatize(porter_stemmer.stem(line))
                line=line.replace('social listening','social_listening') #'social_listening'是文本中一个重要的词汇,为了防止因分词问题导致的语义丢失,笔者将其替换成带下划线的单个词汇 
                jieba.add_word('social_listening')  #对特定长词进行控制,防止被分错词,影响后续的分析效果      
                jieba.add_word('社会化聆听')  #对social_listening进行控制,防止被分错词,影响后续的分析效果        
                yield [i.strip() for i in jieba.lcut(line) if i not in stoplist and  len(i) > 1]  #在载入文本的同时,对其中的语句进行分词处理,且去掉停用词和长度小于1的语句

sentences = MySentences('./data/')  # 内存友好的迭代器
print(list(sentences)[:30])   #打印其中的30个文档
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值