文章目录
- 1.python自带word2vec包的使用
- 1.1 中文分词
- 1.2 word2vec
- 2. gensim之word2vec的使用
- 参考
在网上搜到有直接使用python自带word2vec包,也有使用gensim中的word2vec包。下面就介绍这两种方法。
首先说明我的环境:使用Ubuntu16,python2.
1.python自带word2vec包的使用
下载的是完整版,如下图。
下载下来的文件名为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的文件,内容如下:
在这个文件中,中文就可以正常显示了。接下来就可以对中文文本进行分词了。
1.1 中文分词
跟我的另一篇博客《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了。
1.2 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()
结果如下:
2. gensim之word2vec的使用
接下来介绍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'江西']
结果: