深度学习 | Word2vec原理及应用

聊聊Word2vec

  • 1 前言
  • 2 什么是Word2vec?
    • 2.1 定义
      • 2.1.1 分词的原理介绍
      • 2.1.2 文本向量化的方式
    • 2.2 数学原理
      • 2.2.1 CBOW(Continuous Bag-of-Words)原理
      • 2.2.2 Skip-Gram原理
      • 2.2.3 为什么要有Word2vec 而不是用原来的?
      • 2.2.4 Word2vec基础:霍夫曼树
      • 2.2.5 Hierarchical Softmax
      • 2.2.6 Negative Sampling
    • 2.3 应用场景
    • 2.4 优缺点
  • 3 Word2vec的Python实现
    • 3.1 导入库
    • 3.2 读入数据
    • 3.3 模型
    • 3.4 应用
      • 3.4.1 应用1
      • 3.4.2 应用2
      • 3.4.3 应用3
      • 3.4.4 应用4
      • 3.4.5 李达康的词向量
      • 3.4.6 侯亮平的词向量
    • 3.5 利用Python计算cosine
  • 参考

1 前言

最近公司项目中涉及到给每个用户推荐app,而在app数据相关处理的过程中,将app变为了一个向量,最后再转变到一个用户用一个向量来表示,而这其中用到的关键技术就是Word2Vec!之前只是大概听过,现在系统性的总结一波~

2 什么是Word2vec?

2.1 定义

首先来看看维基百科定义:

Word2vec:为一群用来产生词向量的相关模型。这些模型为浅层双层的神经网络,用来训练以重新建构语言学之词文本。网络以词表现,并且需猜测相邻位置的输入词,在word2vec中词袋模型假设下,词的顺序是不重要的。
训练完成之后,word2vec模型可用来映射每个词到一个向量,可用来表示词对词之间的关系。该向量为神经网络之隐藏层[1]。
Word2vec依赖skip-grams或连续词袋(CBOW)来建立神经词嵌入。Word2vec为托马斯·米科洛夫(Tomas Mikolov)在Google带领的研究团队创造。该算法渐渐被其他人所分析和解释[2][3]。

结合上述定义我们可以看到:

  • Word2vec用来产生词向量,但其模型为神经网络模型,词向量为模型的输入,最后是通过梯度上升法不断的优化迭代这个词向量。
  • Word2vec迭代产生的词向量可以自己指定向量维度

这时候不禁就会问一句,为什么要搞一个词向量?词汇为啥要表示成向量呢?

2.1.1 分词的原理介绍

在下面介绍文本向量化的时候会涉及到分词,首先介绍下分词的基本原理。

  • 本质是一个N元模型,即目前位置的词汇和前面N个词汇有关。
  • 在NLP中,为了简化计算,我们通常使用马尔科夫假设,即每一个分词出现的概率仅仅和前一个分词有关
  • MCMC采样时,也用到了相同的假设来简化模型复杂度。使用了马尔科夫假设,则我们的联合分布就好求了。
  • 优化求解方法:维比特算法。
    • 句子过长,对应很多种分词方法的时候,直接暴力求每种出现的概率然后选最优的算法复杂度过高
    • 通用的求序列最短路径的方法。用概率图来进行表示
    • 应用:隐式马尔科夫模型HMM解码算法求解;最优分词求解

2.1.2 文本向量化的方式

文本无法直接参与建模进行后续分析,而转化成向量之后就可以进行!所以如何将文本变为向量就是一个大学问~

但归纳起来,可以理解为两种方式

  • 方式1:基于one-hot编码的变形
    • 变形1:基于频数(词袋模型,BoW)的向量化表示
    • 变形2:基于Hash Trick的向量化表示
    • 变形3:基于TF-IDF的向量化表示
  • 方式2:Word2vec

方式1:基于频数(词袋模型,BoW)的向量化表示

  • 首先对预料进行分词+预设词典+去停用词
  • 统计出所有出现的词汇,同时定义位置,如果某一句话有该位置上的词,则在该位置上的取值为 该词出现的频数
  • 对每句话按照上述方式进行向量化表示!

可以结合下面结果知道,这种方法本质还是one-hot,只不过这时候的1表示为频数!而不仅仅是表示有没有出现!

Python实现:

from sklearn.feature_extraction.text import CountVectorizer  
vectorizer=CountVectorizer()
corpus=["I come to China to travel", 
    "This is a car polupar in China",          
    "I love tea and Apple ",   
    "The work is to write some papers in science"] 
print (vectorizer.fit_transform(corpus))
  (0, 4)	1
  (0, 15)	2
  (0, 3)	1
  (0, 16)	1
  (1, 3)	1
  (1, 14)	1
  (1, 6)	1
  (1, 2)	1
  (1, 9)	1
  (1, 5)	1
  (2, 7)	1
  (2, 12)	1
  (2, 0)	1
  (2, 1)	1
  (3, 15)	1
  (3, 6)	1
  (3, 5)	1
  (3, 13)	1
  (3, 17)	1
  (3, 18)	1
  (3, 11)	1
  (3, 8)	1
  (3, 10)	1

按位置定义的所有词汇如下:

print (vectorizer.fit_transform(corpus).toarray())
print('词向量的维度为: ', len(vectorizer.fit_transform(corpus).toarray()[0]))
print (vectorizer.get_feature_names())
[[0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 2 1 0 0]
 [0 0 1 1 0 1 1 0 0 1 0 0 0 0 1 0 0 0 0]
 [1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0]
 [0 0 0 0 0 1 1 0 1 0 1 1 0 1 0 1 0 1 1]]
词向量的维度为:  19
['and', 'apple', 'car', 'china', 'come', 'in', 'is', 'love', 'papers', 'polupar', 'science', 'some', 'tea', 'the', 'this', 'to', 'travel', 'work', 'write']

方式2:基于Hash Trick的向量化表示

什么叫Hash Trick呢?为什么要用Hash Trick?

  • Hash Trick是为了避免基于词频而维度过大的情形!
  • 首先定义一个特征Hash后对应的哈希表的大小,这个哈希表的维度会远远小于我们的词汇表的特征维度,因此可以看成是降维
  • 具体方法:对应任意一个特征名,我们会用Hash函数找到对应哈希表的位置,然后将该特征名对应的词频统计值累加到该哈希表位置
  • 变形:signed hash trick。
    • 解决的问题:两个原始特征的哈希后位置在一起导致词频累加特征值突然变大
    • 好处:哈希后的特征仍然是一个无偏的估计,不会导致某些哈希位置的值过大。
  • 但Hash trick解释性比基于词频的要差。

对比基于词频的向量化+Hash Trick后的向量化:

基于词频的向量化应用场景:

  • 词汇表的特征不太大
  • 优势:
    • 解释性很强,我们知道每一维特征对应哪一个词
    • 同时还可以使用TF-IDF对各个词特征的权重修改,进一步完善特征的表示。

基于Hash Trick的向量化应用场景:

  • 大规模机器学习
  • 优势:
    • 降维速度很快,降维后的特征仍可以帮我们完成后续的分类和聚类工作
    • 解决了词汇量极大,使用向量化方法内存不够用的问题

Python实现:

将上述19维的转变为6维

from sklearn.feature_extraction.text import HashingVectorizer 
vectorizer2=HashingVectorizer(n_features = 6,norm = None)
print (vectorizer2.fit_transform(corpus))
  (0, 1)	2.0
  (0, 2)	-1.0
  (0, 4)	1.0
  (0, 5)	-1.0
  (1, 0)	1.0
  (1, 1)	1.0
  (1, 2)	-1.0
  (1, 5)	-1.0
  (2, 0)	2.0
  (2, 5)	-2.0
  (3, 0)	0.0
  (3, 1)	4.0
  (3, 2)	-1.0
  (3, 3)	1.0
  (3, 5)	-1.0
print (vectorizer2.fit_transform(corpus).toarray())
print('词向量的维度为: ', len(vectorizer2.fit_transform(corpus).toarray()[0]))
[[ 0.  2. -1.  0.  1. -1.]
 [ 1.  1. -1.  0.  0. -1.]
 [ 2.  0.  0.  0.  0. -2.]
 [ 0.  4. -1.  1.  0. -1.]]
词向量的维度为:  6

方式3:基于TF-IDF的向量化表示

首先TF-IDF在之前的博客中小编已经介绍过,详情可以戳:机器学习 | TF-IDF和TEXT-RANK的区别

在此处,大概流程和上述1很类似,就是将词频换成了该词汇的TF-IDF得分!

  • 首先对预料进行分词+预设词典+去停用词
  • 统计出所有出现的词汇,同时定义位置,如果某一句话有该位置上的词,则在该位置上的取值为 该词的TF-IDF得分
  • 对每句话按照上述方式进行向量化表示!

至于为什么基于频数进行优化也很好理解,比如有些话中to很多,词频会很大,但其意义可能并不大,TF-IDF就可以有效解决这个问题!

Python实现:

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf2 = TfidfVectorizer()
corpus=["I come to China to travel", 
    "This is a car polupar in China",          
    "I love tea and Apple ",   
    "The work is to write some papers in science"] 
re = tfidf2.fit_transform(corpus)
print (re)
  (0, 16)	0.4424621378947393
  (0, 3)	0.348842231691988
  (0, 15)	0.697684463383976
  (0, 4)	0.4424621378947393
  (1, 5)	0.3574550433419527
  (1, 9)	0.45338639737285463
  (1, 2)	0.45338639737285463
  (1, 6)	0.3574550433419527
  (1, 14)	0.45338639737285463
  (1, 3)	0.3574550433419527
  (2, 1)	0.5
  (2, 0)	0.5
  (2, 12)	0.5
  (2, 7)	0.5
  (3, 10)	0.3565798233381452
  (3, 8)	0.3565798233381452
  (3, 11)	0.3565798233381452
  (3, 18)	0.3565798233381452
  (3, 17)	0.3565798233381452
  (3, 13)	0.3565798233381452
  (3, 5)	0.2811316284405006
  (3, 6)	0.2811316284405006
  (3, 15)	0.2811316284405006

向量维度以及各维度表示的含义为:

tfidf2.get_feature_names()
['and',
 'apple',
 'car',
 'china',
 'come',
 'in',
 'is',
 'love',
 'papers',
 'polupar',
 'science',
 'some',
 'tea',
 'the',
 'this',
 'to',
 'travel',
 'work',
 'write']
print('词向量的维度为: ', len(tfidf2.fit_transform(corpus).toarray()[0]))
tfidf2.fit_transform(corpus).toarray()
词向量的维度为:  19





array([[0.        , 0.        , 0.        , 0.34884223, 0.44246214,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.69768446, 0.44246214, 0.        , 0.        ],
       [0.        , 0.        , 0.4533864 , 0.35745504, 0.        ,
        0.35745504, 0.35745504, 0.        , 0.        , 0.4533864 ,
        0.        , 0.        , 0.        , 0.        , 0.4533864 ,
        0.        , 0.        , 0.        , 0.        ],
       [0.5       , 0.5       , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.5       , 0.        , 0.        ,
        0.        , 0.        , 0.5       , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.28113163, 0.28113163, 0.        , 0.35657982, 0.        ,
        0.35657982, 0.35657982, 0.        , 0.35657982, 0.        ,
        0.28113163, 0.        , 0.35657982, 0.35657982]])

可以看到此时to就没有this重要,虽然频数大!

方式4:Word2vec

归结起来,Word2vec为2种模型+2种求解优化方法,故总共为4种方案,下面在数学原理篇将进行详细介绍!

2.2 数学原理

  • 2种模型:CBOW和Skip-Gram
  • 2种求解优化方法:Hierarchical Softmax和Negative Sampling

首先在Word2vec之前已经有两种模型在做词向量的工作,那就是CBOW和Skip-Gram,而Word2vec就是在这个基础上加入了两种优化方法:Hierarchical Softmax和Negative Sampling,于是就产生了4种Word2vec模型:

  • CBOW+Hierarchical Softmax
  • CBOW+Negative Sampling
  • Skip-Gram+Hierarchical Softmax
  • Skip-Gram+Negative Sampling

2.2.1 CBOW(Continuous Bag-of-Words)原理

模型作用:用来训练产生词向量

  • 三层的神经网络结构(当然也可以多层),分为输入层,隐藏层和输出层(softmax层)。
  • 训练输入:某个词的上下文相关词对应的词向量,训练输出:该词
  • 由于CBOW使用的是词袋模型,因此这8个词都是平等的,也就是不考虑他们和我们关注的词之间的距离大小,只要在我们上下文之内即可。
  • CBOW神经网络模型输入层8个神经元输出层词汇表大小个神经元

举例:
深度学习 | Word2vec原理及应用_第1张图片

  • 训练输入:上述8个词对应的词向量(一开始先初始化8个词的词向量,后面通过神经网络不断迭代)
  • 训练输出:learning对应词向量【训练的目标是期望训练样本特定词对应的softmax概率最大】
  • 不断训练迭代优化词向量

最后前向计算预测的时候,

  • 输入:某个词汇上下文的词汇的向量
  • 输出:对应所有词汇的softmax概率

2.2.2 Skip-Gram原理

  • 思路和上述CBOW相反,已知某个词汇,输出该词汇对应上下文。

  • 即输入:特定的一个词的词向量;输出:特定词对应的上下文词向量。

  • 还是上面的例子,我们的上下文大小取值为4, 特定的这个词"Learning"是我们的输入,而这8个上下文词是我们的输出

  • Skip-Gram神经网络模型输入层有1个神经元,输出层有词汇表大小个神经元

  • 训练输入:输入是特定词的词向量

  • 训练输出:输出是上下文的8个词的词向量

最后前向计算预测的时候,

  • 输入:某个词汇的词向量
  • 输出:概率大小排前8的softmax概率对应的神经元所对应的词即可。

2.2.3 为什么要有Word2vec 而不是用原来的?

  • 原因是传统的DNN算法最后输出层是softmax激活函数,并且输出层为词汇表大小的神经元,因此计算量太大!效率低!
  • 总结就是:DNN的输出层需要进行softmax计算各个词的输出概率的的计算量很大

2.2.4 Word2vec基础:霍夫曼树

  • Word2vec数据结构是用霍夫曼树来代替隐藏层和输出层的神经元
    • 霍夫曼树的叶子节点起到输出层神经元的作用
    • 叶子节点的个数即为词汇表的大小
    • 内部节点则起到隐藏层神经元的作用
  • 建立过程:
    深度学习 | Word2vec原理及应用_第2张图片
    建立树ok之后,我们进行编码:

    • 约定左子树编码为1右子树编码为0,同时约定左子树的权重不小于右子树的权重。
    • 权重高的叶子节点越靠近根节点,而权重低的叶子节点会远离根节点,这样我们的高权重节点编码值较短,而低权重值编码值较长。
    • 保证树的带权路径最短,也符合我们的信息论,即我们希望越常用的词拥有更短的编码

    具体见下图:
    深度学习 | Word2vec原理及应用_第3张图片

    2.2.5 Hierarchical Softmax

  • 优化1:对于从输入层到隐藏层的映射,没有采取神经网络的线性变换加激活函数的方法,而是采用简单的对所有输入词向量求和并取平均的方法
  • 优化2:从隐藏层到输出的softmax层这里的计算量改进。
    • 避免要计算所有词的softmax概率
    • 采用了霍夫曼树来代替从隐藏层到输出softmax层的映射(softmax概率计算只需要沿着树形结构进行就可以了,二叉树)
    • 如何“沿着霍夫曼树一步步完成”呢?在word2vec中,我们采用了二元逻辑回归的方法,即规定沿着左子树走,那么就是负类(霍夫曼树编码1),沿着右子树走,那么就是正类(霍夫曼树编码0)。判别正类和负类的方法是使用sigmoid函数
  • CBOW+Hierarchical Softmax:梯度迭代使用了随机梯度上升法

    深度学习 | Word2vec原理及应用_第4张图片

    Skip-Gram+Hierarchical Softmax:梯度迭代使用了随机梯度上升法

    深度学习 | Word2vec原理及应用_第5张图片

    2.2.6 Negative Sampling

    为什么有上面Hierarchical Softmax还要有Negative Sampling呢?因为它也有自身的局限性。

    Hierarchical Softmax的优缺点为:

    • 优点:使用霍夫曼树来代替传统的神经网络,可以提高模型训练的效率
    • 缺点:如果我们的训练样本里的中心词?是一个很生僻的词,那么就得在霍夫曼树中辛苦的向下走很久了。

    那我们来看看Negative Sampling,听这个名字大家就可以看出,这是一种采样的方法,如何采样呢?

    • 比如我们有一个训练样本,中心词是?,它周围上下文共有2?个词,记为???????(?)。
    • 由于这个中心词?,的确和???????(?)相关存在,因此它是一个真实的正例。通过Negative Sampling采样,我们得到neg个和?不同的中心词??,?=1,2,…???,这样???????(?)和??就组成了neg个并不真实存在的负例。【所以是通过取不同的中心词,原有的中心词对应的就是正样本】
    • 利用这一个正例和neg个负例,我们进行二元逻辑回归,得到负采样对应每个词??对应的模型参数??,和每个词的词向量。

    接下来有两个问题:

    • 如何做逻辑回归?正常的套路!
    • 如何选取其余的中心词做负采样?
      • 如果词汇表的大小为?,那么我们就将一段长度为1的线段分成?份,每份对应词汇表中的一个词。
      • 每个词对应的线段长度是不一样的,高频词对应的线段长低频词对应的线段短

    CBOW+Negative Sampling

    深度学习 | Word2vec原理及应用_第6张图片

    Skip-Gram+Negative Sampling

    深度学习 | Word2vec原理及应用_第7张图片

    2.3 应用场景

    • word2vec的主要的应用还是自然语言的处理,通过训练出来的词向量,可以进行聚类等处理,或者作为其他深度学习的输入。
    • word2vec还适用于一些时序数据的挖掘,比如用户商品的浏览分析、用户APP的下载等,通过这些数据的分析,可以得到商品或者APP的向量表示,从而用于个性化搜索和推荐。

    2.4 优缺点

    优点:

    • word2vec通过一系列的模型和框架对原有的NNLM进行优化,简化了计算但准确度还是保持得很好

    缺点:

    • 解释性较差。

    3 Word2vec的Python实现

    3.1 导入库

    import numpy as np
    import gensim
    
    from gensim.models import word2vec
    
    import jieba
    import jieba.analyse
    
    jieba.suggest_freq('沙瑞金', True)
    jieba.suggest_freq('田国富', True)
    jieba.suggest_freq('高育良', True)
    jieba.suggest_freq('侯亮平', True)
    jieba.suggest_freq('钟小艾', True)
    jieba.suggest_freq('陈岩石', True)
    jieba.suggest_freq('欧阳菁', True)
    jieba.suggest_freq('易学习', True)
    jieba.suggest_freq('王大路', True)
    jieba.suggest_freq('蔡成功', True)
    jieba.suggest_freq('孙连城', True)
    jieba.suggest_freq('季昌明', True)
    jieba.suggest_freq('丁义珍', True)
    jieba.suggest_freq('郑西坡', True)
    jieba.suggest_freq('赵东来', True)
    jieba.suggest_freq('高小琴', True)
    jieba.suggest_freq('赵瑞龙', True)
    jieba.suggest_freq('林华华', True)
    jieba.suggest_freq('陆亦可', True)
    jieba.suggest_freq('刘新建', True)
    jieba.suggest_freq('刘庆祝', True)
    
    Building prefix dict from the default dictionary ...
    Dumping model to file cache /var/folders/vx/np6lccw52hdfcz_2qswpfhch0000gn/T/jieba.cache
    Loading model cost 1.243 seconds.
    Prefix dict has been built succesfully.
    1
    

    3.2 读入数据

    with open('./in_the_name_of_people.txt',encoding='utf-8') as f:
        document = f.read()
        
        #document_decode = document.decode('GBK')
        
        document_cut = jieba.cut(document)
        #print  ' '.join(jieba_cut)  //如果打印结果,则分词效果消失,后面的result无法显示
        result = ' '.join(document_cut)
    #     result = result.encode('utf-8')
        with open('./in_the_name_of_people_segment.txt', 'w', encoding='utf-8') as f2:
            f2.write(result)
    f.close()
    f2.close()
    

    3.3 模型

    # import modules & set up logging
    import logging
    import os
    from gensim.models import word2vec
    
    logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
    
    sentences = word2vec.LineSentence('./in_the_name_of_people_segment.txt') 
    
    model = word2vec.Word2Vec(sentences, hs=1,min_count=1,window=3,size=100)
    
    '''
    1、模型默认用CBOW【即已知上下文 求中间的!】 sg=0
    2、优化方法默认用negative sampling hs=0  而hs=1表示用hierarchical softmax
    3、词向量的默认为:size 即100 [Dimensionality of the word vectors]
    '''
    
    2019-08-18 17:20:52,719 : INFO : collecting all words and their counts
    2019-08-18 17:20:52,722 : INFO : PROGRESS: at sentence #0, processed 0 words, keeping 0 word types
    2019-08-18 17:20:52,815 : INFO : collected 17878 word types from a corpus of 161343 raw words and 2311 sentences
    2019-08-18 17:20:52,816 : INFO : Loading a fresh vocabulary
    2019-08-18 17:20:52,850 : INFO : effective_min_count=1 retains 17878 unique words (100% of original 17878, drops 0)
    2019-08-18 17:20:52,852 : INFO : effective_min_count=1 leaves 161343 word corpus (100% of original 161343, drops 0)
    2019-08-18 17:20:52,919 : INFO : deleting the raw counts dictionary of 17878 items
    2019-08-18 17:20:52,923 : INFO : sample=0.001 downsamples 38 most-common words
    2019-08-18 17:20:52,924 : INFO : downsampling leaves estimated 120578 word corpus (74.7% of prior 161343)
    2019-08-18 17:20:52,944 : INFO : constructing a huffman tree from 17878 words
    2019-08-18 17:20:53,601 : INFO : built huffman tree with maximum node depth 17
    2019-08-18 17:20:53,645 : INFO : estimated required memory for 17878 words and 100 dimensions: 33968200 bytes
    2019-08-18 17:20:53,647 : INFO : resetting layer weights
    2019-08-18 17:20:54,001 : INFO : training model with 3 workers on 17878 vocabulary and 100 features, using sg=0 hs=1 sample=0.001 negative=5 window=3
    2019-08-18 17:20:54,373 : INFO : worker thread finished; awaiting finish of 2 more threads
    2019-08-18 17:20:54,387 : INFO : worker thread finished; awaiting finish of 1 more threads
    2019-08-18 17:20:54,399 : INFO : worker thread finished; awaiting finish of 0 more threads
    2019-08-18 17:20:54,401 : INFO : EPOCH - 1 : training on 161343 raw words (120392 effective words) took 0.4s, 305531 effective words/s
    2019-08-18 17:20:54,678 : INFO : worker thread finished; awaiting finish of 2 more threads
    2019-08-18 17:20:54,686 : INFO : worker thread finished; awaiting finish of 1 more threads
    2019-08-18 17:20:54,693 : INFO : worker thread finished; awaiting finish of 0 more threads
    2019-08-18 17:20:54,694 : INFO : EPOCH - 2 : training on 161343 raw words (120560 effective words) took 0.3s, 417119 effective words/s
    2019-08-18 17:20:54,893 : INFO : worker thread finished; awaiting finish of 2 more threads
    2019-08-18 17:20:54,894 : INFO : worker thread finished; awaiting finish of 1 more threads
    2019-08-18 17:20:54,907 : INFO : worker thread finished; awaiting finish of 0 more threads
    2019-08-18 17:20:54,908 : INFO : EPOCH - 3 : training on 161343 raw words (120517 effective words) took 0.2s, 567584 effective words/s
    2019-08-18 17:20:55,198 : INFO : worker thread finished; awaiting finish of 2 more threads
    2019-08-18 17:20:55,207 : INFO : worker thread finished; awaiting finish of 1 more threads
    2019-08-18 17:20:55,218 : INFO : worker thread finished; awaiting finish of 0 more threads
    2019-08-18 17:20:55,219 : INFO : EPOCH - 4 : training on 161343 raw words (120712 effective words) took 0.3s, 391368 effective words/s
    2019-08-18 17:20:55,526 : INFO : worker thread finished; awaiting finish of 2 more threads
    2019-08-18 17:20:55,533 : INFO : worker thread finished; awaiting finish of 1 more threads
    2019-08-18 17:20:55,553 : INFO : worker thread finished; awaiting finish of 0 more threads
    2019-08-18 17:20:55,554 : INFO : EPOCH - 5 : training on 161343 raw words (120478 effective words) took 0.3s, 362484 effective words/s
    2019-08-18 17:20:55,555 : INFO : training on a 806715 raw words (602659 effective words) took 1.6s, 388087 effective words/s
    

    3.4 应用

    3.4.1 应用1

    找出某一个词向量最相近的词集合

    req_count = 5
    for key in model.wv.similar_by_word('李达康', topn =100):
        if len(key[0])==3:
            req_count -= 1
            print (key[0], key[1])
            if req_count == 0:
                break;
    
    2019-08-18 17:21:44,506 : INFO : precomputing L2-norms of word weight vectors
    
    
    侯亮平 0.9604056477546692
    欧阳菁 0.9600167274475098
    蔡成功 0.9599809646606445
    刘新建 0.9572819471359253
    祁同伟 0.9565152525901794
    
    
    /Users/apple/anaconda3/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.
      if np.issubdtype(vec.dtype, np.int):
    
    req_count = 5
    for key in model.wv.similar_by_word('沙瑞金', topn =100):
        if len(key[0])==3:
            req_count -= 1
            print (key[0], key[1])
            if req_count == 0:
                break;
    
    高育良 0.9720388650894165
    田国富 0.9549083709716797
    易学习 0.9494497776031494
    李达康 0.9454081058502197
    侯亮平 0.9189556241035461
    
    
    /Users/apple/anaconda3/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.
      if np.issubdtype(vec.dtype, np.int):
    

    3.4.2 应用2

    看两个词向量的相近程度

    print (model.wv.similarity('沙瑞金', '高育良'))
    print (model.wv.similarity('李达康', '王大路'))
    
    0.9720388
    0.9373346
    
    
    /Users/apple/anaconda3/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.
      if np.issubdtype(vec.dtype, np.int):
    
    print (model.wv.similarity('沙瑞金', '刘庆祝'))
    
    0.8436507
    
    
    /Users/apple/anaconda3/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.
      if np.issubdtype(vec.dtype, np.int):
    

    3.4.3 应用3

    找出不同类的词

    print (model.wv.doesnt_match("沙瑞金 高育良 李达康 刘庆祝".split()))
    
    刘庆祝
    
    
    /Users/apple/anaconda3/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.
      if np.issubdtype(vec.dtype, np.int):
    

    刘庆祝和另外三个人不是同一类人!

    3.4.4 应用4

    得到词向量

    # 语料库有多少单词
    model.corpus_total_words
    
    161343
    
    model.corpus_count
    
    2311
    
    model.vocabulary
    
    
    

    3.4.5 李达康的词向量

    model['李达康']
    
    /Users/apple/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:1: DeprecationWarning: Call to deprecated `__getitem__` (Method will be removed in 4.0.0, use self.wv.__getitem__() instead).
      if __name__ == '__main__':
    
    
    
    
    
    array([-0.0870866 ,  0.05248798, -0.28147143, -0.32899868, -0.24419424,
           -0.26717356,  0.68835247,  0.4199263 ,  0.07673895,  0.34578642,
           -0.18166232, -0.64018744,  0.0661103 ,  1.3144252 ,  0.23052616,
           -0.9842175 ,  0.16689244, -1.0376722 , -0.6779322 , -0.08552188,
            0.8821609 ,  0.85630375,  0.70850575,  0.02350087, -0.26186958,
           -0.19465029, -0.5280784 ,  0.02718589, -0.22725886,  0.584188  ,
           -0.22170487,  0.17096068,  0.22743836, -0.58258903, -0.8521926 ,
            0.01146634,  0.17366898, -0.20080233,  0.49060255, -0.0892161 ,
            0.2798695 , -0.48753452, -0.26934424, -0.28810668, -0.50305516,
           -0.52781904, -1.0276003 , -0.29357475, -0.5148399 , -0.99778444,
            0.82347995, -0.17103711,  0.45900956, -0.25982574, -0.10443403,
           -0.43294677, -0.03601839,  0.23268174, -0.0897947 , -0.30117008,
            0.13093895, -0.04065455,  0.98853856, -0.19679072,  0.02730171,
           -0.39002168, -0.86443186, -0.30278337, -0.35015163,  0.45706993,
           -0.35796672, -0.5281926 ,  0.4609695 , -0.16861178, -0.4281448 ,
           -0.05549743,  0.30860028, -0.33855316, -0.8916333 ,  0.77231795,
           -0.45779762,  0.29819477, -0.05069054,  0.41183752, -0.25177717,
           -0.20057783,  0.53893435,  0.13017803,  0.8262993 ,  0.77265227,
           -0.57259095, -0.02957028, -0.03229868,  0.4734169 ,  0.02673261,
           -0.56793886,  0.48301852, -0.14260153, -0.21643269,  0.4321306 ],
          dtype=float32)
    
    len(model['李达康'])
    
    /Users/apple/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:1: DeprecationWarning: Call to deprecated `__getitem__` (Method will be removed in 4.0.0, use self.wv.__getitem__() instead).
      if __name__ == '__main__':
    
    
    
    
    
    100
    

    3.4.6 侯亮平的词向量

    model['侯亮平']
    
    /Users/apple/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:1: DeprecationWarning: Call to deprecated `__getitem__` (Method will be removed in 4.0.0, use self.wv.__getitem__() instead).
      if __name__ == '__main__':
    
    
    
    
    
    array([-0.27619898,  0.27101442, -0.3888319 , -0.21565337, -0.1988687 ,
           -0.21134071,  0.58008534,  0.6338025 ,  0.26411813,  0.300347  ,
            0.0545746 , -0.7266006 , -0.06810553,  1.4180936 ,  0.04470716,
           -1.2312315 ,  0.2570867 , -1.356324  , -0.74197394, -0.03976419,
            0.89614266,  0.73904985,  0.9443898 ,  0.13467237, -0.09986281,
           -0.27338284, -0.6192025 , -0.19986346, -0.3509883 ,  0.8633056 ,
           -0.1322346 ,  0.02944488,  0.00851353, -0.8523627 , -0.69786495,
            0.17855184,  0.27958298, -0.1690526 ,  0.74027956, -0.09224971,
            0.27419734, -0.6110898 , -0.45265457, -0.33315966, -0.5103257 ,
           -0.63461596, -1.1950399 ,  0.09368438, -0.29370093, -1.0550132 ,
            0.93446714, -0.30718964,  0.6203983 , -0.26469257, -0.3890905 ,
           -0.34891984, -0.02781189,  0.56555355,  0.03353672, -0.03311604,
           -0.03772071,  0.28559205,  1.2120959 , -0.19666088,  0.21143027,
           -0.7012241 , -1.0564705 , -0.24415188, -0.35654724,  0.54533786,
           -0.70228875, -0.6307003 ,  0.5166867 , -0.3769945 , -0.25609592,
           -0.09554568,  0.2651889 , -0.56329715, -1.3013954 ,  0.9396692 ,
           -0.38046873,  0.25952345, -0.18691233,  0.3837758 , -0.557426  ,
           -0.388514  ,  0.68085045,  0.12305634,  1.1934747 ,  0.73448956,
           -0.6552626 ,  0.00999391,  0.10919277,  0.717848  ,  0.0193353 ,
           -0.6280944 ,  0.39228523,  0.05402936, -0.11338637,  0.58770233],
          dtype=float32)
    
    len(model['侯亮平'])
    
    /Users/apple/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:1: DeprecationWarning: Call to deprecated `__getitem__` (Method will be removed in 4.0.0, use self.wv.__getitem__() instead).
      if __name__ == '__main__':
    
    
    
    
    
    100
    

    3.5 利用Python计算cosine

    import numpy as np
    
    
    def cos_sim(vector_a, vector_b):
        """
        计算两个向量之间的余弦相似度
        :param vector_a: 向量 a 
        :param vector_b: 向量 b
        :return: sim
        """
        vector_a = np.mat(vector_a)
        vector_b = np.mat(vector_b)
        num = float(vector_a * vector_b.T) # 两个向量乘积
        denom = np.linalg.norm(vector_a) * np.linalg.norm(vector_b) # 两个向量各自模长的乘积
        cos = num / denom 
        sim = 0.5 + 0.5 * cos # 归一化
        return sim
    

    参考

    • wiki:https://zh.wikipedia.org/wiki/Word2vec
    • 文本挖掘预处理之向量化与Hash Trick:https://www.cnblogs.com/pinard/p/6688348.html
    • 文本挖掘预处理之TF-IDF:https://www.cnblogs.com/pinard/p/6693230.html
    • 文本挖掘的分词原理:https://www.cnblogs.com/pinard/p/6677078.html
    • word2vec原理(一) CBOW与Skip-Gram模型基础:https://www.cnblogs.com/pinard/p/7160330.html
    • word2vec原理(二) 基于Hierarchical Softmax的模型:https://www.cnblogs.com/pinard/p/7243513.html
    • word2vec原理(三) 基于Negative Sampling的模型:https://www.cnblogs.com/pinard/p/7249903.html
    • word2vec学习小记:https://www.jianshu.com/p/418f27df3968
    • 用gensim学习word2vec:https://www.cnblogs.com/pinard/p/7278324.html

    你可能感兴趣的:(Python,机器学习,深度学习)