最近两天在学习Word2Vec这个算法,它是NLP领域中非常常用的基础算法,它的作用就是将语料库中的词转化为向量,以便后续在词向量的基础上进行各种计算。这个算法的讲解可以从网络上很容易搜索到,这里就不赘述。
Word2Vec算法已经被实现和封装在Python库gensim中,可以很简单的调用。然而在这两天的尝试中,我发现由于gensim的API发生了变化,很多博客的内容已经不能使用,而且他们的使用说明也不是很清楚,所以决定写下这一篇博文。本文内容参考gensim官网教程,结合现有的博文,所有内容都经过亲自尝试,在当前gensim版本下应该完全work的。
安装很简单,就用pip安装:
pip install --upgrade gensim
或者对于conda的环境:
conda install -c conda-forge gensim
目前最新版本:3.4.0
依赖的相关环境:
Python >= 2.7 (tested with versions 2.7, 3.5 and 3.6)
NumPy >= 1.11.3
SciPy >= 0.18.1
Six >= 1.5.0
smart_open >= 1.2.1
常用的导入训练数据的方法有两种,第一种是使用Python的内置列表,一个简单的栗子:
# 导入gensim库
from gensim.models import Word2Vec
# 第一种输入方式:Python内置列表
sentences = [['first', 'sentence'], ['second', 'sentence']]
# 调用函数训练模型
model = Word2Vec(sentences) # 调用之后,Word2Vec的模型就训练好了
注意,sentences是一个“二维列表”,一个句子的单词在一个列表中,所有句子的列表在同一个列表中,即:[['第', '一', '个', '句子'], ['第', '二', '个', '句子']]
。如果这里搞错了,训练会很慢,而且训练出来的模型会不好使。
当数据集特别大的时候,使用上述第一种方法就需要消耗特别多的内存,gensim还支持使用迭代生成器的方式输入:
class MySentences(object):
def __init__(self, dirname):
self.dirname = dirname
def __iter__(self):
for fname in os.listdir(self.dirname):
for line in open(os.path.join(self.dirname, fname)):
yield line.split()
sentences = MySentences('/some/directory') # 第二种输入方式:占用内存少的迭代器
model = Word2Vec(sentences)
这个第二种输入方式会依次打开“/some/directory”文件夹中的每个数据文件,对于每个文件一行一行的读取数据进模型,这样就避免了一次性读入而占用太多内存。
Word2vec接受一些参数来调整训练速度与训练质量,常用的有:
model = Word2Vec(sentences, size=100, window=5, min_count=1, workers=4)
除了sentences是必须有的输入数据外,其他几个都是可选的,它们分别是:
训练好的Word2Vec模型可以保存下来,之后可以从保存的模型中重新加载回来:
model.save('word2vec.model') # 保存模型
loaded_model = Word2Vec.load('word2vec.model') # 加载模型
训练好的模型可以增加语料继续训练:
model.train([["hello", "world"]], total_examples=1, epochs=1)
新版gensim把训练后得到的词向量与模型分离出来,放在了model.wv
这个KeyedVectors实例中。这样的好处是,训练完之后,如果之后不用再继续训练,我们可以就此将占用大内存的模型本身丢掉,只留下这个词向量的结果,而且可以使用mmap更快速的加载和分享:
from gensim.models import KeyedVectors
wv = model.wv # 得到训练之后的词向量
del model # 删除占用大内存的model
wv.save('word_vector') # 保存word vectors
loaded_wv = KeyedVectors.load('word_vector', mmap='r') # 加载保存的word vectors
几个常用的内置功能函数,举例子来说明:
# 得到词的词向量
wv['man']
# 得到所有词的词表
wv.vocab.keys()
# 计算两个词之间的余弦相似度
wv.similarity('man', 'woman')
# 计算一个词d(或者词表)和相似度,使得该词的向量v(d)与v(a="woman")-v(c="man")+v(b="king")最近
wv.most_similar(positive=["woman","king"],negative=["man"],topn=10) #topn是返回最近的词的个数,默认返回前10个
# 返回与“man”最近的词和相似度
wv.similar_by_word("man", topn=10)
# 找出不太合群的词
model.doesnt_match("breakfast cereal dinner lunch".split()) #这个结果是cereal
更多内置函数请参考官方API。
更多API和详细说明请移步一下参考资料,特别是第2和第6项(官方说明)。有任何错误或者不足还请各位大侠在评论区留言!
谢谢!