赞
踩
在网上搜到有直接使用python自带word2vec包,也有使用gensim中的word2vec包。下面就介绍这两种方法。
首先说明我的环境:使用Ubuntu16,python2.
数据:来源于搜狗实验室的搜狐新闻数据。下载的是完整版,如下图。
下载下来的文件名为news_sohusite_xml.full.tar.gz。
使用下面的命令将其解压缩,会得到一个名为news_sohusite_xml.dat的文件:
tar -zvxf news_sohusite_xml.full.tar.gz
news_sohusite_xml.dat文件内容如下,在我电脑上显示为乱码,但是在别的博客中看到的是正常文字,这个不影响后面的操作,可以忽略:
接下来使用下面的命令,取出文件的内容:
cat news_tensite_xml.dat | iconv -f gbk -t utf-8 -c | grep “” > corpus.txt
得到一个名为corpus.txt的文件,内容如下:
在这个文件中,中文就可以正常显示了。接下来就可以对中文文本进行分词了。
跟我的另一篇博客《NLP基础–中文分词、去停用词小Demo》中的代码基本一致,只是拿到了分词后的文件,在一般的NLP处理中,会需要去停用词。由于word2vec的算法依赖于上下文,而上下文有可能就是停词。因此对于word2vec,我们可以不用去停词。
代码如下:
import jieba import sys reload(sys) sys.setdefaultencoding('utf-8') filePath = 'corpus.txt' fileSegWordDonePath = 'corpusSegDone.txt' # read the file by line fileTrainRead = [] with open(filePath) as fileTrainRaw: for line in fileTrainRaw: fileTrainRead.append(line) # define this function to print a list with Chinese def PrintListChinese(list): for i in range(len(list)): print list[i], # segment word with jieba fileTrainSeg=[] for i in range(len(fileTrainRead)): # 对[9:-11]分词 (如行22中所示: fileTrainRead[i][9:-11] ),这样可以去掉每行(一篇新闻稿)起始的<content> 和结尾的</content>。 fileTrainSeg.append([' '.join(list(jieba.cut(fileTrainRead[i][9:-11],cut_all=False)))]) if i % 100 == 0: print i # to test the segment result PrintListChinese(fileTrainSeg[10]) # save the result with open(fileSegWordDonePath, 'wb') as fW: for i in range(len(fileTrainSeg)): fW.write(fileTrainSeg[i][0].encode('utf-8')) fW.write('\n')
经过十分钟左右,就会得到名为corpusSegDone.txt的文件,在这个文件中是分好词的文本。
接下来就可以使用word2vec了。
首先是安装word2vec,命令很简单:
pip install word2vec
我在安装时,出现一个错误,ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output. 在网上搜不到结果,仔细看了报错信息,发现word2vec的安装依赖于Cython这样一个库,就先pip install Cython之后,再安装word2vec就可以了。
接下来就可以使用这个包来构建词向量了,只需要调用word2vec函数即可。
import word2vec
word2vec.word2vec('corpusSegDone.txt', 'corpusWord2Vec.bin',
size=300, verbose=True)
网上对这个函数的说明很少,基本上都是关于gensim下面的word2vec的介绍,所以这里介绍的可能不太准确。下面的代码是其源码中的参数解释。
def word2vec(train, output, size=100, window=5, sample='1e-3', hs=0, negative=5, threads=12, iter_=5, min_count=5, alpha=0.025, debug=2, binary=1, cbow=1, save_vocab=None, read_vocab=None, verbose=False): """ word2vec execution Parameters for training: train <file> Use text data from <file> to train the model output <file> Use <file> to save the resulting word vectors / word clusters size <int> Set size of word vectors; default is 100 window <int> Set max skip length between words; default is 5 sample <float> Set threshold for occurrence of words. Those that appear with higher frequency in the training data will be randomly down-sampled; default is 0 (off), useful value is 1e-5 hs <int> Use Hierarchical Softmax; default is 1 (0 = not used) negative <int> Number of negative examples; default is 0, common values are 5 - 10 (0 = not used) threads <int> Use <int> threads (default 1) min_count <int> This will discard words that appear less than <int> times; default is 5 alpha <float> Set the starting learning rate; default is 0.025 debug <int> Set the debug mode (default = 2 = more info during training) binary <int> Save the resulting vectors in binary moded; default is 0 (off) cbow <int> Use the continuous back of words model; default is 1 (use 0 for skip-gram model) save_vocab <file> The vocabulary will be saved to <file> read_vocab <file> The vocabulary will be read from <file>, not constructed from the training data verbose Print output from training """
在corpusSegDone.txt文件上进行训练模型,这个数据集在我电脑上是2.2G,所以训练时间在十几分钟左右,训练完成后,就可以得到corpusWord2Vec.bin文件。
接下来就可以使用词向量了:
# -*- coding: utf-8 -*-
import word2vec
model = word2vec.load('corpusWord2Vec.bin')
#查看词向量
print (model.vectors)
# 查看词向量对应的词
index = 100
print model.vocab[index]
print '-----------------'
# 查看空间距离相近的词
res = []
indexes = model.cosine(u'加拿大')
for index in indexes[0]:
print model.vocab[index]
结果:
上面需要注意的是,如果你在下载数据集时,想着“我只是做个小Demo,那我不需要下载完整版,只下载一个迷你版的吧”,那么你在上面的这一步就会卡住。你会发现indexes = model.cosine(u’加拿大’)这一行代码会报错KeyError,刚开始我以为是编码的问题,反复修改之后还是不行。后来发现KeyError反映出的不是编码问题,是因为迷你版数据提取的词中没有‘加拿大’这个词。于是试了几个迷你版数据中有的词“上海”、“市民”、“幸福”等。但是这些词虽然解决了这一步的问题,到下面的代码之后,发现由于数据集太小,下面的结果不好,于是还是又下载了完整版的数据,从头再来。
接下来可以对词向量采用PCA进行降维,得到二维的词向量,并打印出来,代码如下:
# coding=utf-8 import numpy as np import matplotlib import matplotlib.pyplot as plt from sklearn.decomposition import PCA import word2vec # load the word2vec model model = word2vec.load('corpusWord2Vec.bin') rawWordVec = model.vectors # reduce the dimension of word vector X_reduced = PCA(n_components=2).fit_transform(rawWordVec) # show some word(center word) and it's similar words index1, metrics1 = model.cosine(u'中国') index2, metrics2 = model.cosine(u'清华') index3, metrics3 = model.cosine(u'牛顿') index4, metrics4 = model.cosine(u'自动化') index5, metrics5 = model.cosine(u'刘亦菲') # add the index of center word index01 = np.where(model.vocab == u'中国') index02 = np.where(model.vocab == u'清华') index03 = np.where(model.vocab == u'牛顿') index04 = np.where(model.vocab == u'自动化') index05 = np.where(model.vocab == u'刘亦菲') index1 = np.append(index1, index01) index2 = np.append(index2, index03) index3 = np.append(index3, index03) index4 = np.append(index4, index04) index5 = np.append(index5, index05) # plot the result zhfont = matplotlib.font_manager.FontProperties(fname='/usr/share/fonts/truetype/wqy/wqy-microhei.ttc') fig = plt.figure() ax = fig.add_subplot(111) for i in index1: ax.text(X_reduced[i][0], X_reduced[i][1], model.vocab[i], fontproperties=zhfont, color='r') for i in index2: ax.text(X_reduced[i][0], X_reduced[i][1], model.vocab[i], fontproperties=zhfont, color='b') for i in index3: ax.text(X_reduced[i][0], X_reduced[i][1], model.vocab[i], fontproperties=zhfont, color='g') for i in index4: ax.text(X_reduced[i][0], X_reduced[i][1], model.vocab[i], fontproperties=zhfont, color='k') for i in index5: ax.text(X_reduced[i][0], X_reduced[i][1], model.vocab[i], fontproperties=zhfont, color='c') ax.axis([-0.4, 0.8, -0.4, 0.4]) plt.show()
结果如下:
接下来介绍python中gensim包如何使用word2vec。
gensim是一个很好用的Python NLP的包,不光可以用于使用word2vec,还有很多其他的API可以用。它封装了google的C语言版的word2vec。当然我们可以可以直接使用C语言版的word2vec来学习,但是个人认为没有gensim的python版来的方便。
安装gensim是很容易的,使用"pip install gensim"即可。
下面是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=,iter=5,null_word=0, trim_rule=None, sorted_vocab=1, batch_words=10000)
参数:
· sentences:可以是一个list,对于大语料集,建议使用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(defau·t),则negative sampling会被使用。
· negative: 如果>0,则会采用negativesamp·ing,用于设置多少个noise words
· cbow_mean: 如果为0,则采用上下文词向量的和,如果为1(defau·t)则采用均值。只有使用CBOW的时候才起作用。
· hashfxn: hash函数来初始化权重。默认使用python的hash函数
· iter: 迭代次数,默认为5
· trim_rule: 用于设置词汇表的整理规则,指定那些单词要留下,哪些要被删除。可以设置为None(min_count会被使用)或者一个接受()并返回RU·E_DISCARD,uti·s.RU·E_KEEP或者uti·s.RU·E_DEFAU·T的函数。
· sorted_vocab: 如果为1(defau·t),则在分配word index 的时候会先对单词基于频率降序排序。
· batch_words:每一批的传递给线程的单词的数量,默认为10000
在这里,继续使用搜狗实验室的搜狐新闻数据集,直接使用分词完成后的文件corpusSegDone.txt
,代码如下:
# -*- coding: utf-8 -*-
import logging
from gensim.models import word2vec
# 用于打印日志
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
sentences = word2vec.LineSentence('./corpusSegDone.txt')
# 开始训练模型
model = word2vec.Word2Vec(sentences, hs=1, min_count=1, window=3, size=100, iter=3)
# 保存模型
model.save('sougoudata.model')
在我的电脑上,平均一个iter需要12分钟。
保存模型之后,就可以再加载模型进行其他的工作:
# -*- coding: utf-8 -*- from gensim.models import Word2Vec model = Word2Vec.load('sougoudata.model') print model.wv.similarity('中国'.decode('utf-8'), '加拿大'.decode('utf-8')) req_count = 5 for key in model.wv.similar_by_word('加拿大'.decode('utf-8'), topn =100): req_count -= 1 print key[0], key[1] if req_count == 0: break; print model.wv.similarity('家具'.decode('utf-8'), '沙发'.decode('utf-8')) print model.wv.similarity('家具'.decode('utf-8'), '飞机'.decode('utf-8')) # print model.wv.index2word # 获得所有的词汇 print len(model.wv.index2word) # for word in model.wv.index2word: # print word, model[word] # 获得词汇及其对应的向量 # 获得词汇及其对应的向量 print model[u'江西']
结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。