基于Gensim的Word2Vec的应用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lilong117194/article/details/82182869

一:word2vec的基础简介可以参考:
https://blog.csdn.net/lilong117194/article/details/82018008
https://blog.csdn.net/lilong117194/article/details/82085172
https://blog.csdn.net/lilong117194/article/details/81979522

二:gensim安装很简单,也有很多资料可以参考,这里不再介绍
三:gensim word2vec API概述:

在gensim中,word2vec 相关的API都在包gensim.models.word2vec中。和算法有关的参数都在类gensim.models.word2vec.Word2Vec中。算法需要注意的参数有:

  • sentences: 我们要分析的语料,可以是一个列表,或者从文件中遍历读出。后面我们会有从文件读出的例子。
  • size: 词向量的维度,默认值是100。这个维度的取值一般与我们的语料的大小相关,如果是不大的语料,比如小于100M的文本语料,则使用默认值一般就可以了。如果是超大的语料,建议增大维度。
  • window:即词向量上下文最大距离,这个参数在我们的算法原理篇中标记为,window越大,则和某一词较远的词也会产生上下文关系。默认值为5。在实际使用中,可以根据实际的需求来动态调整这个window的大小。如果是小语料则这个值可以设的更小。对于一般的语料这个值推荐在[5,10]之间。
  • sg: 即我们的word2vec两个模型的选择了。如果是0, 则是CBOW模型,是1则是Skip-Gram模型,默认是0即CBOW模型。
  • hs: 即我们的word2vec两个解法的选择了,如果是0, 则是Negative Sampling,是1的话并且负采样个数negative大于0, 则是Hierarchical Softmax。默认是0即Negative Sampling。
  • negative:即使用Negative Sampling时负采样的个数,默认是5。推荐在[3,10]之间。这个参数在我们的算法原理篇中标记为neg。
  • cbow_mean: 仅用于CBOW在做投影的时候,为0,则算法中的为上下文的词向量之和,为1则为上下文的词向量的平均值。默认值也是1,不推荐修改默认值。
  • min_count:需要计算词向量的最小词频。这个值可以去掉一些很生僻的低频词,默认是5。如果是小语料,可以调低这个值。
  • iter: 随机梯度下降法中迭代的最大次数,默认是5。对于大语料,可以增大这个值。
  • alpha: 在随机梯度下降法中迭代的初始步长。算法原理篇中标记为,默认是0.025。
  • min_alpha: 由于算法支持在迭代的过程中逐渐减小步长,min_alpha给出了最小的迭代步长值。随机梯度下降中每轮的迭代步长可以由iter,alpha, min_alpha一起得出。这部分由于不是word2vec算法的核心内容。对于大语料,需要对alpha, min_alpha,iter一起调参,来选择合适的三个值。

1. 《人民的名义》的文本分析

《人民的名义》原始文本下载
拿到了原文,我们首先要进行分词,这里使用结巴分词完成,当然也要提前安装jieba包。分词的结果放到另一个文件中。最后将分词后的结果保存在文件中。注意其中的编码的问题,保存时是utf-8,处理时是gbk。同时,分词时添加一些人名和专有名词,增加分词后的效果。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Aug 29 10:14:43 2018

@author: lilong
"""

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)


with open('./in_the_name_of_people.txt','rb') 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')
    print('here....')
    with open('./in_the_name_of_people_segment.txt', 'wb+') as f2:
        f2.write(result)

f.close()
f2.close()


import logging
from gensim.models import word2vec

"""
读分词后的文件到内存,这里使用了word2vec提供的LineSentence类来读文件,然后使用word2vec的模型
"""
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
sentences = word2vec.Text8Corpus('./in_the_name_of_people_segment.txt') 
model = word2vec.Word2Vec(sentences, hs=1,min_count=1,window=3,size=100) 
print('................\n')

"""
模型出来了,我们可以用来做什么呢?第一个是最常用的,找出某一个词向量最相近的词集合
"""

# 计算两个词向量的相似度
try:
    sim1 = model.similarity(u'沙瑞金',u'高育良')
    sim2 = model.similarity(u'李达康',u'易学习')
except KeyError:
    sim1 = 0
    sim2 = 0
print(u'沙瑞金 和 高育良 的相似度为 ',sim1)
print(u'李达康 和 易学习 的相似度为 ',sim2)

print('--------------------------------------------')
# 与某个词(李达康)最相近的3个字的词
print(u'与李达康最相近的3个字的词')
req_count = 5
for key in model.similar_by_word(u'李达康',topn =100):
    if len(key[0])==3:
        req_count -=1
        print(key[0],key[1])
        if req_count ==0:
            break

print('--------------------------------------------')
# 计算某个词(侯亮平)的相关列表
try:
    sim3 = model.most_similar(u'侯亮平',topn =20)
    print(u'和 侯亮平 与相关的词有:\n')
    for key in sim3:
        print(key[0],key[1])
except:
    print(' error')

print('--------------------------------------------')
# 找出不同类的词
sim4 = model.doesnt_match(u'沙瑞金 高育良 李达康 刘庆祝'.split())
print("u'沙瑞金 高育良 李达康 刘庆祝'人物中不同类的人名是:",sim4)

print('--------------------------------------------')
# 保留模型,方便重用
model.save(u'人民的名义.model')

运行结果:

...
...
attribute vectors_norm
2018-08-29 14:23:05,278 : INFO : not storing attribute cum_table
................

沙瑞金 和 高育良 的相似度为  0.9786563
李达康 和 易学习 的相似度为  0.95864296
--------------------------------------------
与李达康最相近的3个字的词
侯亮平 0.9804731607437134
祁同伟 0.9705764651298523
陆亦可 0.966049313545227
易学习 0.9586428999900818
沙瑞金 0.95697021484375
--------------------------------------------
和 侯亮平 与相关的词有:

李达康 0.9804732799530029
陆亦可 0.9691306352615356
祁同伟 0.9667516350746155
季昌明 0.9624065160751343
高育良 0.9539155960083008
易学习 0.9508687257766724
沙瑞金 0.9425103664398193
郑西坡 0.940951406955719
陈岩石 0.9330751895904541
赵东来 0.9168741106987
孙连城 0.9126583337783813
王大路 0.9110490083694458
吴慧芬 0.908033549785614
马上 0.9079679846763611
梁璐 0.9045602083206177
欧阳菁 0.9008608460426331
挥挥手 0.8979870676994324
私下里 0.8971830606460571
刘新建 0.8965901732444763
孙书记 0.8965592980384827
--------------------------------------------
这类人物中不同类的人名 刘庆祝
--------------------------------------------
2018-08-29 14:23:05,645 : INFO : saved 人民的名义.model

这里注意:

#对应的加载方式
model_2 = word2vec.Word2Vec.load('人民的名义.model')
# 以一种c语言可以解析的形式存储词向量  
model.save_word2vec_format(u"书评.model.bin", binary=True)  
# 对应的加载方式  
model_3 =word2vec.Word2Vec.load_word2vec_format("书评.model.bin",binary=True) 

打印输出的结果中还有很多的日志信息,这是因为logging模块的作用。

1.1 logging模块用于打印日志

logging.basicConfig()函数实现打印日志的基础配置,配置传入的各参数参考下文:

logging.basicConfig函数各参数:
filename: 指定日志文件名
filemode: 和file函数意义相同,指定日志文件的打开模式,’w’或’a’
format: 指定输出的格式和内容,format可以输出很多有用信息:

logging.basicConfig(
            level=logging.DEBUG,
            format='levelname:%(levelname)s 进程ID %(process)d, \n filename: %(filename)s ',
            filename='/tmp/test.log',
            datefmt='[%d/%b/%Y %H:%M:%S]',
            filemode='a'
           )

logging.debug('This is debug message')
logging.info('This is info message')

%(levelno)s: 打印日志级别的数值
%(levelname)s: 打印日志级别名称
%(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
%(filename)s: 打印当前执行程序名
%(funcName)s: 打印日志的当前函数
%(lineno)d: 打印日志的当前行号
%(asctime)s: 打印日志的时间
%(thread)d: 打印线程ID
%(threadName)s: 打印线程名称
%(process)d: 打印进程ID
%(message)s: 打印日志信息
datefmt: 指定时间格式,同time.strftime()
level: 设置日志级别,默认为logging.WARNING
stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略

logging打印信息函数:
logging.debug(‘This is debug message’)
logging.info(‘This is info message’)
logging.warning(‘This is warning message’)

1.2 用gensim函数库训练Word2Vec模型的配置参数

这里对gensim文档的Word2Vec函数的参数说明
class gensim.models.word2vec.Word2Vec(sentences=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, cbow_mean=1, hashfxn=<built-in function hash>,iter=5,null_word=0, trim_rule=None, sorted_vocab=1, batch_words=10000)

参数:

  • sentences:可以是一个·ist,对于大语料集,建议使用BrownCorpus,Text8Corpus ineSentence构建。
  • sg: 用于设置训练算法,默认为0,对应CBOW算法;sg=1则采用skip-gram算法。
  • size:是指特征向量的维度,默认为100。大的size需要更多的训练数据,但是效果会更好. 推荐值为几十到几百。
  • window:表示当前词与预测词在一个句子中的最大距离是多少
  • alpha: 是学习速率
  • seed:用于随机数发生器。与初始化词向量有关。
  • min_count: 可以对字典做截断. 词频少于min_count次数的单词会被丢弃掉, 默认值为5
  • max_vocab_size: 设置词向量构建期间的RAM限制。如果所有独立单词个数超过这个,则就消除掉其中最不频繁的一个。每一千万个单词需要大约1GB的RAM。设置成None则没有限制。
  • sample: 高频词汇的随机降采样的配置阈值,默认为1e-3,范围是(0,1e-5)
  • workers参数控制训练的并行数。
  • hs: 如果为1则会采用hierarchica softmax技巧。如果设置为0(defaut),则negative sampling会被使用。
  • negative: 如果>0,则会采用negative samping,用于设置多少个noise words
  • cbow_mean: 如果为0,则采用上下文词向量的和,如果为1(defaut)则采用均值。只有使用CBOW的时候才起作用。
  • hashfxn: hash函数来初始化权重,默认使用python的hash函数
  • iter: 迭代次数,默认为5
  • trim_rule: 用于设置词汇表的整理规则,指定那些单词要留下,哪些要被删除。
  • sorted_vocab: 如果为1(defaut),则在分配word index 的时候会先对单词基于频率降序排序。
  • batch_words:每一批的传递给线程的单词的数量,默认为10000

2. 基于gensim训练百科语料库

1.下载原始数据:
数据下载地址:https://dumps.wikimedia.org/zhwiki/latest/zhwiki-latest-pages-articles.xml.bz2
下载的文件是一个大小为1.3G的压缩包,解压后是个5.8G左右的xml文件,内容是网页标签形式的。我们需要抽取出其中的有效信息。

2.数据预处理:
这里使用gensim自带的数据提取方法

from gensim.corpora import WikiCorpus

space=" "
with open('wiki-zh-article.txt','w',encoding="utf8") as f:
    wiki=WikiCorpus('zhwiki-latest-pages-articles.xml.bz2',lemmatize=False,dictionary={})
    for text in wiki.get_texts():
        print('Write to new file..')
        f.write(space.join(text)+"\n")

print("Finished Save...")

大概运行了20分钟左右。。。

3.繁体字处理
维基百科的中文数据是繁简混杂的,里面包含大陆简体、台湾繁体、港澳繁体等多种不同的数据。有时候在一篇文章的不同段落间也会使用不同的繁简字。

为了处理方便起见,我们直接使用了开源项目opencc。参照安装说明的方法,安装完成之后,使用下面的命令进行繁简转换,整个过程也很快:

  • ubuntu下输入以下命令:
$ sudo apt-get install opencc
$ opencc -i wiki-zh-article.txt -o corpus.txt -c zht2zhs.ini

其中wiki-zh-article.txt为输入文本文件,也是要处理的文件。 corpus.txt为化简后的文本文件。zht2zhs.ini 是转换方式,默认的是zhs2zht.ini,即简体字转为繁体字。

  • mac下输入以下命令:
    apt-get是Ubuntu才有的包管理器,而此时可以使用brew代替apt-get。
    brew 全称Homebrew,是Mac OSX上的软件包管理工具,能在Mac中方便的安装软件或者卸载软件。
    安装只需要在终端下输入下面一条命令(Mac自带ruby不需要安装)
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

安装完成后使用brew install opencc即可
然后会让输入管理员密码,而这里我的密码不知道,所以就没有亲自验证。。

4.分词
一般都会使用jieba分词,这一点和上面的案例是一样的,这里就
5.运行word2vec训练
这里和上面的例子也是一样的,可以参考上面的实例。

总结:词向量的构建很简单,就是语料的获得,然后分词,直接送到模型进行训练,最终得到相应的词向量。

参考:
https://www.cnblogs.com/pinard/p/7278324.html

猜你喜欢

转载自blog.csdn.net/lilong117194/article/details/82182869