自然语言处理之词向量模型聚类分析
Word Embedding
词嵌入向量(Word Embedding)是NLP里面一个重要的概念,我们可以利用Word Embedding一个单词固定长度向量的表示一种表示形式。Word Embedding矩阵给每个单词分配一个固定长度的向量表示,这个长度可以自行设定,这个长度相对于one hot模型的词典长度维数上要小很多,但是却可以表示更多的信息,因为Word Embedding向量中每个维度都有含义。
Word2Vec
Word2Vec是生成Word Embedding的方式,Word2Vec有很对方法例如Continuous Bag Of Words (CBOW)、Skip-gram等,本次作业中使用了CBOW模型。
NN
基于神经网络的分布表示又称为词向量、词嵌入,神经网络词向量模型与其它分布表示方法一样,均基于分布假说,核心依然是上下文的表示以及上下文与目标词之间的关系的建模。 2001年, Bengio 等人正式提出神经网络语言模型( Neural Network Language Model ,NNLM),该模型在学习语言模型的同时,也得到了词向量。
输入是One-Hot Vector,Hidden Layer没有激活函数,也就是线性的单元。Output Layer维度跟Input Layer的维度一样,用的是SoftMax回归。当这个模型训练好以后,我们并不会用这个训练好的模型处理新的任务,我们真正需要的是这个模型通过训练数据所学得的参数,例如隐层的权重矩阵。
这个模型是如何定义数据的输入和输出呢?一般分为CBOW与Skip-Gram两种模型。CBOW模型的训练输入是某一个特征词的上下文相关的词对应的词向量,而输出就是这特定的一个词的词向量。Skip-Gram模型和CBOW的思路是反着来的,即输入是特定的一个词的词向量,而输出是特定词对应的上下文词向量。CBOW对小型数据库比较合适,而Skip-Gram在大型语料中表现更好。
CBOW
而如果是拿一个词语的上下文作为输入,来预测这个词语本身,则是CBOW模型。
1 输入层:上下文单词的one hot. {假设单词向量空间dim为V,上下文单词个数为C}
2 所有one hot分别乘以共享的输入权重矩阵W. {VN矩阵,N为自己设定的数,初始化权重矩阵W}
3 所得的向量 {因为是one hot所以为向量} 相加求平均作为隐层向量, size为1N.
4 乘以输出权重矩阵W’ {NV}
5 得到向量 {1V} 激活函数处理得到V-dim概率分布
6 概率最大的index所指示的单词为预测出的中间词(target word)与true label的one hot做比较,误差越小越好(根据误差更新权重矩阵)
所以,需要定义loss function(一般为交叉熵代价函数),采用梯度下降算法更新W和W’。训练完毕后,输入层的每个单词与矩阵W相乘得到的向量的就是我们想要的词向量(word embedding),这个矩阵(所有单词的word embedding)也叫做look up table(就是矩阵W自身),也就是说,任何一个单词的one hot乘以这个矩阵都将得到自己的词向量。有了look up table就可以免去训练过程直接查表得到单词的词向量了。
Skip-gram
如果是用一个词语作为输入,来预测它周围的上下文,那这个模型叫做Skip-gram模型。
PCA
PCA(Principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据降维算法。PCA的主要思想是将n维特征映射到k维上,这k维是全新的正交特征也被称为主成分,是在原有n维特征的基础上重新构造出来的k维特征。
K-means
k均值聚类算法(k-means clustering algorithm)是一种迭代求解的聚类分析算法,其步骤是,预将数据分为K组,则随机选取K个对象作为初始的聚类中心,然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。每分配一个样本,聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差平方和局部最小。
程序实现
运行环境
Anaconda 4.9.2
断句分词
按'。' '\n'
标点进行断句,删除标点,并用'\n'
表示一句的结束,最后调用Jiaba库进行分词。
def sepSentences(self):
line = ''
sentences_list = []
for w in self.txt:
if w in ['。', '\n'] and line != '\n':
if line.strip() != '':
sentences_list.append(line.strip())
line = ''
elif w not in self.punctuation:
line += w
self.sentences = sentences_list
def sepWords(self):
words_list = []
dete_stopwords_flag = 1
if dete_stopwords_flag:
for i in range(len(self.sentences)):
words_list.extend([x for x in jieba.cut(
self.sentences[i]) if x not in self.stopwords])
words_list.append('\n')
else:
for i in range(len(self.sentences)):
words_list.extend([x for x in jieba.cut(self.sentences[i])])
words_list.append('\n')
words_str = ' '.join(words_list)
self.words = words_str
生成词向量
调用gensim库,读取断句分词后的保存的文件,转换为词向量。
def train(self):
self.sepSentences()
self.sepWords()
with open('./SentenceFile/' + self.txtname + '_句子.txt', 'w', encoding='UTF-8') as f2:
f2.write(self.words)
self.sent_iter = word2vec.LineSentence(
'./SentenceFile/' + self.txtname + '_句子.txt')
self.model = word2vec.Word2Vec(self.sent_iter, workers=1)
主成分分析与聚类
调用Sklearn库中的PCA与K-means,对词向量进行主成分分析降温,聚类。
keys = Character
# 获取词向量
wordvector = []
for key in keys:
wordvector.append(d.model.wv[key])
# 降维
wordvector_ = PCA(n_components=2).fit_transform(wordvector)
# 分类
labels_ = KMeans(n_clusters=4).fit_predict(wordvector_)
结果输出
# 可视化
plt.scatter(wordvector_[:, 0], wordvector_[:, 1], c=labels_)
for i in range(len(keys)):
plt.annotate(text=keys[i], xy=(
wordvector_[:, 0][i], wordvector_[:, 1][i]))
plt.show()
运行结果
测试用例
倚天屠龙记.txt
关键词
Character = ['张无忌', '赵敏', '谢逊', '周芷若', '张翠山', '杨逍', '灭绝师太', '张三丰', '殷离', '殷素素', '小昭', '殷梨亭',
'韦一笑', '俞岱岩', '胡青牛', '宋远桥', '殷天正', '周颠', '纪晓芙', '宋青书', '杨不悔', '金花婆婆', '说不得',
'范遥', '丁敏君', '陈友谅', '常遇春', '鹿杖客', '莫声谷', '鹤笔翁', '朱元璋', '阳顶天', '郭襄', '成昆', '空见',
'冷谦','彭莹玉']
Kungfu = ['太极拳', '太极剑', '真武七截阵', '九阳神功', '峨嵋九阳功', '少林九阳功', '乾坤大挪移', '九阴真经', '九阴白骨爪',
'七伤拳', '九阳真经', '玄冥神掌']
sect = ['明教', '峨嵋派', '天鹰教', '昆仑派', '崆峒派', '武当派', '少林派', '神拳门', '华山派']
输出相近词
# 查找相近的词
for key in d.model.wv.similar_by_word('张无忌', topn=10):
print(key[0], key[1])
与张无忌关系比较近的词:
赵敏 0.9944162368774414
殷素素 0.9893664717674255
张翠山 0.9883266091346741
谢逊 0.9879009127616882
低声 0.9870488047599792
周芷若 0.9858320355415344
无忌 0.9820763468742371
罢 0.9808448553085327
微笑 0.976464569568634
周颠 0.9755969047546387
比较相似度
# 两词相近程度
print(d.model.wv.similarity('武当', '张三丰'))
比较武当与张三丰的相近度:
0.9800525
输出聚类结果
可以大致从中看出其中人物关系,例如张无忌与赵敏、张翠山、殷素素、周芷若关系较近,玄冥二老的鹿仗客与鹤笔翁关系较近。
人物关系:
武功关系:
门派关系: