中文分词word2vec和doc2vec句向量的理解

**

Doc2vec

**
1.Word2vec和Doc2vec做Word Embedding和Sentence/Document EMbedding。
2.NLP中最直观常用的一种词表示方法是one-hot方法,这种方法把每个词表示为一个很长的向量。这个向量的维度是词表大小,其中绝大多数元素为 0,只有一个维度的值为 1,这个维度就代表了当前的词。
举个例子来说:“科比”可能表示为[0001000000…],而“篮球”可以表示为[0000000100000…]
3.one-hot的表示方法是一种稀疏表示方式,虽然在很多情况下one-hot表示方法已经取得了不错的效果,但是这种词表示方法也引起了一些问题。首先,one-hot表示方法可能造成维数灾难,如果词表很大,则每一个词就表示为除了该词所在的索引处为1外,其他全为0的一个很长的向量,这会给机器运算造成很大的困难。其次,one-hot表示方法表示的两个词的词向量是孤立的,不能从两个词的向量中看出两个词之间的语义关系。

4.使用one-hot表示向量的问题:
A.不能分辨细节差别(美丽==漂亮)
B.需要大量人为劳动(专家文本分析)
C.主观(以前和现在词的意思发生变化)
D.无法发现新词(不能主动发现词,and放在那里)
E.难以精确计算词之间的相似度
5.One_hot:
语料库:John likes to watch moives.Mary likes too.
John also likes to watch football games.
词典:{”John”:1,”likes”:2,…”too”:10} ===》 {词:index}
One_hot 【每个单词都有唯一的索引】
Jone[1,0,0,0,0,0,0,0,0,0]
‘’’’’
too[0,0,0,0,0,0,0,0,0,0,1]
6.离散表示问题:
a)无法衡量词向量之间的关系
酒店[0,1,0,0,0,…]
宾馆[0,0,0,01,0,0,…]
太过于稀疏,难以捕捉文本含义
b)词表维度随着语料库增长膨胀
c)N-gram 序列语料库膨胀快
d)数据稀疏问题
一.“词向量”简介
1.word2vec提供了高质量的词向量,并在一些任务中表现良好。
关于word2vec的原理可以参考这几篇论文:
https://arxiv.org/pdf/1310.4546.pdf
https://arxiv.org/pdf/1301.3781.pdf
2.关于如何使用第三方库gensim训练word2vec可以参考这篇博客:
调用:from gensim.models import Word2Vec
http://blog.csdn.net/john_xyz/article/details/54706807
3.2013 年 Mikolov 提出了 word2vec 来学习单词的向量表示,
主要有两种方法,cbow ( continuous bag of words)连续词袋 和 skip-gram ,
一个是上下文来预测目标单词,

另一个是用中心单词来预测上下文。

输入层 隐藏层 输出层

4.尽管word2vec提供了高质量的词汇向量,仍然没有有效的方法将它们结合成一个高质量的文档向量。对于一个句子、文档或者说一个段落,怎么把这些数据投影到向量空间中,并具有丰富的语义表达呢?过去人们常常使用以下几种方法:
bag of words
LDA
average word vectors
tfidf-weighting word vectors
就bag of words(词袋)而言,有如下缺点:1.没有考虑到单词的顺序,2.忽略了单词的语义信息。
average word vectors(平均词向量)就是简单的对句子中的所有词向量取平均。是一种简单有效的方法,但缺点也是没有考虑到单词的顺序
tfidf-weighting word vectors(词频权重)是指对句子中的所有词向量根据tfidf权重加权求和,是常用的一种计算sentence embedding的方法,在某些问题上表现很好,相比于简单的对所有词向量求平均,考虑到了tfidf权重,因此句子中更重要的词占得比重就更大。但缺点也是没有考虑到单词的顺序
LDA模型当然就是计算出一片文档或者句子的主题分布。。但缺点也是没有考虑到单词的顺序
LDA模型了解:
https://www.cnblogs.com/pinard/p/6244265.html
二、Doc2vec
Doc2vec又叫Paragraph Vector是Tomas Mikolov基于word2vec模型提出的,其具有一些优点,比如不用固定句子长度,接受不同长度的句子做训练样本,Doc2vec是一个无监督学习算法,该算法用于预测一个向量来表示不同的文档,该模型的结构潜在的克服了词袋模型的缺点。
根据训练文档向量的网络结构不同,可分为Distributed Memory Model(DM)与Distributed bag of words(DBOW)两种模型,其中DM模型不仅考虑了词的上下文语义特征,还考虑到了词序信息。DBOW模型则忽略了上下文词序信息,而专注于文档中的各个词的语义信息。我们同时采用了DM和DBOW这两种文档向量表示方法,从而保证构建的特征中信息的完整性。
Doc2vec是基于Word2vec基础上构建的,相比于Word2vec,Doc2vec不仅能训练出词向量还能训练出句子向量并预测新的句子向量。word2vec里预测词向量时,预测出来的词是含有词义的,比如上文提到的词向量’powerful’会相对于’Paris’离’strong’距离更近,在Doc2vec中也构建了相同的结构。所以Doc2vec克服了词袋模型中没有语义的缺点。假设现在存在训练样本,每个句子是训练样本。和word2vec一样,Doc2vec也有两种训练方式:
1.PV-DM(A distributed memory model of paragraphvectors)
类似于word2vec中的CBOW模型
训练句向量的方法和词向量的方法非常类似。训练词向量的核心思想就是说可以根据每个单词的上下文预测,也就是说上下文的单词对是有影响的。那么同理,可以用同样的方法训练doc2vec。例如对于一个句子i want to drink water,如果要去预测句子中的单词want,那么不仅可以根据其他单词生成feature, 也可以根据其他单词和句子来生成feature进行预测。因此doc2vec的框架如下所示:

1)每个段落/句子都被映射到向量空间中,可以用矩阵的一列来表示。
2)每个单词同样被映射到向量空间,可以用矩阵的一列来表示。
3)然后将段落向量和词向量级联或者求平均得到特征,预测句子中的下一个单词。
这个段落向量/句向量也可以认为是一个单词,它的作用相当于是上下文的记忆单元或者是这个段落的主题,所以我们一般叫这种训练方法为Distributed Memory Model of Paragraph Vectors(PV-DM)分布式记忆模型
在训练的时候我们固定上下文的长度,用滑动窗口的方法产生训练集。段落向量/句向量 在该上下文中共享。
2.PV-DBOW
Paragraph Vector without word ordering: Distributed bag of words
还有一种训练方法是忽略输入的上下文,让模型去预测段落中的随机一个单词。就是在每次迭代的时候,从文本中采样得到一个窗口,再从这个窗口中随机采样一个单词作为预测任务,让模型去预测,输入就是段落向量。如下所示:

我们称这种模型为 Distributed Bag of Words version of Paragraph Vector(PV-DBOW分布式词袋模型)
在上述两种方法中,我们可以使用PV-DM或者PV-DBOW得到段落向量/句向量。对于大多数任务,PV-DM的方法表现很好,但我们也强烈推荐两种方法相结合。
总结doc2vec的过程, 主要有两步:
训练模型,在已知的训练数据中得到词向量, softmax的参数和,以及段落向量/句向量
推断过程(inference stage),对于新的段落,得到其向量表达。具体地,在矩阵中添加更多的列,使用梯度下降的方法得到新的D,从而得到新段落的向量表达

Doc2vec相对于word2vec不同之处在于,在输入层,增添了一个新句子向量Paragraph vector,Paragraph vector可以被看作是另一个词向量,它扮演了一个记忆,词袋模型中,因为每次训练只会截取句子中一小部分词训练,而忽略了除了本次训练词以外该句子中的其他词,这样仅仅训练出来每个词的向量表达,句子只是每个词的向量累加在一起表达的。正如上文所说的词袋模型的缺点,忽略了文本的词序问题。而Doc2vec中的Paragraph vector则弥补了这方面的不足,它每次训练也是滑动截取句子中一小部分词来训练,Paragraph Vector在同一个句子的若干次训练中是共享的,所以同一句话会有多次训练,每次训练中输入都包含Paragraph vector。它可以被看作是句子的主旨,有了它,该句子的主旨每次都会被放入作为输入的一部分来训练。这样每次训练过程中,不光是训练了词,得到了词向量。同时随着一句话每次滑动取若干词训练的过程中,作为每次训练的输入层一部分的共享Paragraph vector,该向量表达的主旨会越来越准确。Doc2vec中PV-DM模型具体的训练过程和word2vec中的CBOW模型训练方式相同,训练完了以后,就会得到训练样本中所有的词向量和每句话对应的句子向量,那么Doc2vec是怎么预测新的句子Paragraph vector呢?其实在预测新的句子的时候,还是会将该Paragraph vector随机初始化,放入模型中再重新根据随机梯度下降不断迭代求得最终稳定下来的句子向量。不过在预测过程中,模型里的词向量还有投影层到输出层的softmax weights参数是不会变的,这样在不断迭代中只会更新Paragraph vector,其他参数均已固定,只需很少的时间就能计算出带预测的Paragraph vector。

代码 实现:

model = gensim.models.Doc2Vec(documents,dm = 0, alpha=0.1, size= 20, min_alpha=0.025)

dm (distributed memory)

model = gensim.models.Doc2Vec(documents,dm = 1, alpha=0.1, size= 20, min_alpha=0.025)

二者在 gensim 实现时的区别是 dm = 0 还是 1.
对Doc2Vec的输入是LabeledSentence对象. 每个这样的对象代表一个句子,由两个简单的列表组成:一个单词列表和一个标签列表。:

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是结合了LDA主题模型、Word2Vec向量模型的TextRank关键词抽取算法的Python代码: ```python import jieba import gensim from gensim import corpora, models import numpy as np from sklearn.metrics.pairwise import cosine_similarity def load_stopwords(path): """ 加载停用词 :param path: 停用词文件路径 :return: 停用词列表 """ stopwords = [] with open(path, 'r', encoding='utf-8') as f: for line in f.readlines(): stopwords.append(line.strip()) return stopwords def get_sentences(text): """ 使用jieba分 :param text: 文本内容 :return: 子列表 """ sentences = [] for line in text.split('\n'): line = line.strip() if not line: continue for s in line.split('。'): s = s.strip() if not s: continue sentences.append(s) return sentences def segment(sentence, stopwords): """ 使用jieba进行分词并去除停用词 :param sentence: 子 :param stopwords: 停用词列表 :return: 分词后的列表 """ words = [] for word in jieba.cut(sentence): word = word.strip() if not word: continue if word not in stopwords: words.append(word) return words def get_word2vec_model(text, size=100, window=5, min_count=5, workers=4): """ 训练Word2Vec模型 :param text: 文本内容 :param size: 词向量维度 :param window: 窗口大小 :param min_count: 最小词频 :param workers: 线程数 :return: Word2Vec模型 """ sentences = [] for line in text.split('\n'): line = line.strip() if not line: continue sentences.append(segment(line, stopwords)) model = gensim.models.Word2Vec(sentences, size=size, window=window, min_count=min_count, workers=workers) return model def get_lda_model(text, num_topics=8, passes=10): """ 训练LDA主题模型 :param text: 文本内容 :param num_topics: 主题数 :param passes: 迭代次数 :return: LDA模型和语料库 """ sentences = [] for line in text.split('\n'): line = line.strip() if not line: continue sentences.append(segment(line, stopwords)) dictionary = corpora.Dictionary(sentences) corpus = [dictionary.doc2bow(sentence) for sentence in sentences] lda_model = models.ldamodel.LdaModel(corpus=corpus, num_topics=num_topics, id2word=dictionary, passes=passes) return lda_model, corpus def get_topic_word_matrix(lda_model, num_topics, num_words): """ 获取主题-词矩阵 :param lda_model: LDA模型 :param num_topics: 主题数 :param num_words: 每个主题选取的关键词数 :return: 主题-词矩阵 """ topic_word_matrix = np.zeros((num_topics, num_words)) for i in range(num_topics): topic_words = lda_model.get_topic_terms(i, topn=num_words) for j in range(num_words): topic_word_matrix[i][j] = topic_words[j][0] return topic_word_matrix def get_sentence_topic_vector(sentence, lda_model, dictionary, num_topics): """ 获取子的主题向量 :param sentence: 子 :param lda_model: LDA模型 :param dictionary: 词典 :param num_topics: 主题数 :return: 子的主题向量 """ sentence_bow = dictionary.doc2bow(segment(sentence, stopwords)) topic_vector = np.zeros(num_topics) for topic, prob in lda_model[sentence_bow]: topic_vector[topic] = prob return topic_vector def get_similarity_matrix(sentences, word2vec_model): """ 获取子之间的相似度矩阵 :param sentences: 子列表 :param word2vec_model: Word2Vec模型 :return: 相似度矩阵 """ similarity_matrix = np.zeros((len(sentences), len(sentences))) for i in range(len(sentences)): for j in range(i+1, len(sentences)): sim = cosine_similarity([np.mean([word2vec_model[word] for word in segment(sentences[i], stopwords) if word in word2vec_model], axis=0)], [np.mean([word2vec_model[word] for word in segment(sentences[j], stopwords) if word in word2vec_model], axis=0)]).item() similarity_matrix[i][j] = sim similarity_matrix[j][i] = sim return similarity_matrix def get_textrank_score(sentences, num_topics, lda_model, word2vec_model): """ 获取TextRank算法得分 :param sentences: 子列表 :param num_topics: 主题数 :param lda_model: LDA模型 :param word2vec_model: Word2Vec模型 :return: 子得分列表 """ dictionary = lda_model.id2word num_words = 20 topic_word_matrix = get_topic_word_matrix(lda_model, num_topics, num_words) sentence_topic_vectors = np.zeros((len(sentences), num_topics)) for i in range(len(sentences)): sentence_topic_vectors[i] = get_sentence_topic_vector(sentences[i], lda_model, dictionary, num_topics) similarity_matrix = get_similarity_matrix(sentences, word2vec_model) # TextRank算法迭代 max_iter = 100 d = 0.85 scores = np.ones(len(sentences)) for i in range(max_iter): tmp_scores = np.zeros(len(sentences)) for j in range(len(sentences)): tmp_scores[j] = (1 - d) + d * np.sum([similarity_matrix[j][k] * scores[k] for k in range(len(sentences))]) scores = tmp_scores # 合并TextRank和主题模型得分 final_scores = np.zeros(len(sentences)) for i in range(len(sentences)): for j in range(num_topics): final_scores[i] += topic_word_matrix[j].tolist().count(i) * sentence_topic_vectors[i][j] final_scores = d * final_scores + (1 - d) * scores return final_scores # 加载停用词 stopwords = load_stopwords('stopwords.txt') # 加载文本 with open('text.txt', 'r', encoding='utf-8') as f: text = f.read() # 分 sentences = get_sentences(text) # 训练Word2Vec模型 word2vec_model = get_word2vec_model(text) # 训练LDA主题模型 lda_model, corpus = get_lda_model(text) # 获取TextRank算法得分 num_topics = 8 scores = get_textrank_score(sentences, num_topics, lda_model, word2vec_model) # 按得分排序,获取关键词 num_keywords = 10 keywords = [] idx = np.argsort(scores)[::-1][:num_keywords] for i in idx: keywords.append(sentences[i]) print(keywords) ``` 其中,text.txt为待处理的文本文件,stopwords.txt为停用词文件,需要自行准备。代码中num_topics、num_words、num_keywords等参数需要根据实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值