文章目录

  • 1.python自带word2vec包的使用
  • 1.1 中文分词
  • 1.2 word2vec
  • 2. gensim之word2vec的使用
  • 参考

在网上搜到有直接使用python自带word2vec包,也有使用gensim中的word2vec包。下面就介绍这两种方法。
首先说明我的环境:使用Ubuntu16,python2.

1.python自带word2vec包的使用

下载的是完整版,如下图。

word2vec嵌入的例子 word2vec实战_python


下载下来的文件名为news_sohusite_xml.full.tar.gz。

使用下面的命令将其解压缩,会得到一个名为news_sohusite_xml.dat的文件:

tar -zvxf news_sohusite_xml.full.tar.gz

news_sohusite_xml.dat文件内容如下,在我电脑上显示为乱码,但是在别的博客中看到的是正常文字,这个不影响后面的操作,可以忽略:

word2vec嵌入的例子 word2vec实战_word2vec嵌入的例子_02


接下来使用下面的命令,取出文件的内容:

cat news_tensite_xml.dat | iconv -f gbk -t utf-8 -c | grep “” > corpus.txt

得到一个名为corpus.txt的文件,内容如下:

word2vec嵌入的例子 word2vec实战_python_03


在这个文件中,中文就可以正常显示了。接下来就可以对中文文本进行分词了。

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]

结果:

word2vec嵌入的例子 word2vec实战_词向量_04


上面需要注意的是,如果你在下载数据集时,想着“我只是做个小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()

结果如下:

word2vec嵌入的例子 word2vec实战_词向量_05

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'江西']

结果:

word2vec嵌入的例子 word2vec实战_词向量_06