gensim学习笔记

1、词向量建模的word2vec模型和用于长文本向量建模的doc2vec模型

  在Gensim中实现word2vec模型非常简单。首先,我们需要将原始的训练语料转化成一个sentence的迭代器;每一次迭代返回的sentence是一个word(utf8格式)的列表:

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') # a memory-friendly iterator

  接下来,我们用这个迭代器作为输入,构造一个Gensim内建的word2vec模型的对象(即将原始的one-hot向量转化为word2vec向量):

model = gensim.models.Word2Vec(sentences)

  我们也可以指定模型训练的参数,例如采用的模型(Skip-gram或是CBoW);负采样的个数;embedding向量的维度等。

  Word2vec对象还支持online learning。我们可以将更多的训练数据传递给一个已经训练好的word2vec对象,继续更新模型的参数:

model = gensim.models.Word2Vec.load('/tmp/mymodel')
model.train(more_sentences)

  若要查看某一个word对应的word2vec向量,可以将这个word作为索引传递给训练好的模型对象:

model['computer']  # raw NumPy vector of a word

  Doc2vec是Mikolov在word2vec基础上提出的另一个用于计算长文本向量的工具。它的工作原理与word2vec极为相似——只是将长文本作为一个特殊的token id引入训练语料中。在Gensim中,doc2vec也是继承于word2vec的一个子类。因此,无论是API的参数接口还是调用文本向量的方式,doc2vec与word2vec都极为相似。

  主要的区别是在对输入数据的预处理上。Doc2vec接受一个由LabeledSentence对象组成的迭代器作为其构造函数的输入参数。其中,LabeledSentence是Gensim内建的一个类,它接受两个List作为其初始化的参数:word list和label list。

from gensim.models.doc2vec import LabeledSentence
sentence = LabeledSentence(words=[u'some', u'words', u'here'], tags=[u'SENT_1'])

类似地,可以构造一个迭代器对象,将原始的训练数据文本转化成LabeledSentence对象:

class LabeledLineSentence(object):
    def __init__(self, filename):
        self.filename = filename
        
    def __iter__(self):
        for uid, line in enumerate(open(filename)):
            yield LabeledSentence(words=line.split(), labels=['SENT_%s' % uid])

准备好训练数据,模型的训练便只是一行命令:

from gensim.models import Doc2Vec
model = Doc2Vec(dm=1, size=100, window=5, negative=5, hs=0, min_count=2, workers=4)

该代码将同时训练word和sentence label的语义向量。如果我们只想训练label向量,可以传入参数train_words=False以固定词向量参数,传入参数训练可用

model.train(sentense)

 

2、ldamodel LDA主题聚类模型

  首先介绍下ldamodel的几个属性和方法。
  • num_terms:获取字典中词的个数,一般就是训练样本中所有不同词的个数;num_topics:获取主题的个数,一般是训练时自己设的,默认值是100;num_updates:获取文档的个数,字面上是获取更新的次数,在这里,每一个文档都是一次更新,所以就是文档个数。
  • get_topic_terms(topicid, topn=10):获取某个主题下的前topn个词语,越相关的在前面,topicid是要显示主题的id值;
  • get_term_topics(word_id, minimum_probability=None):获取某个词最有可能的主题列表,word_id为词id值,minimum_probability为阈值;
  • get_document_topics(bow, minimum_probability=None, minimum_phi_value=None, per_word_topics=False):per_word_topics为False时获取某个文档最有可能具有的主题列表,per_word_topics为True时还得到文档中每个词属于的主题列表,bow为文档,minimum_probability确定主题的阈值,minimum_phi_value判断词属于主题的阈值。

  如果用get_term_topics(word_id),只会获得在整个样本下,某个词属于某些主题的可能性,而并不是针对特定文档的某个词属于某些主题的可能性。显然,使用get_document_topics(bow, per_word_topics=True)可以得到,比如:

  整个返回是个元组,形式为([a],[b],[c]),上图中第一行为a列表,显示的内容是可能性大于minimum_probability的主题及其可能性;第二行为b列表,显示每个词及其可能属于的主题,且其可能性大于minimum_phi_value;第三行为c列表,显示每个词及其可能属于的主题以及可能性。如果只使用get_document_topics(bow)那么只会显示第一行数据。
算法部分,确实主题是根据上下文有变化的,在gensim包中,应用的是EM算法,但却不是原始论文中使用的变分EM算法,当然主要思想是一致的。就像批最优化与随机最优化的关系,哈夫曼的算法中,没有将所有文档整体带入进行迭代计算,而是对每一篇文档进行迭代计算,使得当前文档具有最优的doc-topic和topic-word分布,直至所有文档迭代完。所以在计算新文档时,只需对新文档再进行一次迭代更新(这也是为什么num_updates等于文档数的,因为每个文档都会更新一次)就可获得新文档相应的分布。


posted @ 2018-08-29 19:42  理想几岁  阅读(1887)  评论(0编辑  收藏  举报