本案例以金庸先生的小说《倚天屠龙记》作为语料库,构建Word2Vec模型,从而探究小说中人物的相关性。首先对语料库进行预处理,包括分词、去除标点符号等;预处理之后,调用gensim库根据语料库训练Word2Vec模型,获得每个词的词向量;最后利用余弦相似度度量词向量之间的相似度,从而探究小说中人物的相关性。

1.训练语料库的处理

首先在网上下载小说《倚天屠龙记》,然后将其打开后另存为,注意保存为utf-8的编码格式。

png

保存后,首先对文本进行预处理。使用jieba库的cut函数进行分词,并将逗号、句号、问号等标点符号全部去除。在使用jieba分词的时候,可以针对性地加入用户自定义词典(jieba.load_userdict('userDict.txt')),这样可以提高对人名,地名等未登陆词的识别效果,提高分词性能。将预处理后的文本保存到新的txt文档中,作为训练语料库。注意调用open函数中必须指明编码方式,否则就会报错。

In [1]:
# 此函数作用是对初始语料进行分词处理后,作为训练模型的语料
def cut_txt(old_file):
    import jieba # 导入jieba包
    global cut_file # 分词之后保存的文件名
    cut_file = old_file + '_cut.txt'

    try:
        fi = open(old_file, 'r', encoding='utf-8')
    except BaseException as e:  # 因BaseException是所有错误的基类,用它可以获得所有错误类型
        print(Exception, ":", e)    # 追踪错误详细信息

    text = fi.read()  # 获取文本内容
    new_text = jieba.cut(text, cut_all=False)  # 精确模式
    str_out = ' '.join(new_text).replace(',', '').replace('。', '').replace('?', '').replace('!', '') \
        .replace('“', '').replace('”', '').replace(':', '').replace('…', '').replace('(', '').replace(')', '') \
        .replace('—', '').replace('《', '').replace('》', '').replace('、', '').replace('‘', '') \
        .replace('’', '')     # 去掉标点符号
    fo = open(cut_file, 'w', encoding='utf-8')
    fo.write(str_out)

2.构建并训练Word2Vec模型

准备好训练语料(注意训练语料文件越大越好,越大最后的训练效果越好)之后,就可以开始训练模型了。gensim是一个Python自然语言处理库,能够将文档根据TF-IDF, LDA, LSI等模型转化成向量模式,以便进行进一步的处理。此外,gensim还可以构建Word2Vec模型,能够将单词转化为词向量。关于gensim的使用方法,可参照官网进行学习。本案例只使用gensim中的Word2Vec模型来进行操作。

在gensim中,Word2Vec模型可以通过类gensim.models.word2vec进行调用,其说明如下:

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=<built-in function hash>,iter=5,null_word=0, trim_rule=None, sorted_vocab=1, batch_words=10000)
  1. sentences: 我们要分析的语料,可以是一个列表,或者从文件中遍历读出。对于大语料集,建议使用BrownCorpus,Text8Corpus或lineSentence构建。

  2. size: 词向量的维度,默认值是100。这个维度的取值一般与我们的语料的大小相关,视语料库的大小而定。

  3. alpha:初始的学习速率,在训练过程中会线性地递减至min_alpha。

  4. window:即词向量上下文最大距离,Skip-Gram和CBOW算法是基于滑动窗口来做预测的。默认值为5。在实际使用中,可以根据实际的需求来动态调整这个window的大小。对于一般的语料这个值推荐在[5,10]之间。

  5. min_count::可以对字典做截断. 词频少于min_count次数的单词会被丢弃掉, 默认值为5。

  6. max_vocab_size: 设置词向量构建期间的内存限制,设置成None则没有限制。

  7. sample: 高频词汇的随机降采样的配置阈值,默认为1e-3,范围是(0,1e-5)。

  8. seed:随机数发生器。与初始化词向量有关。

  9. workers:用于控制训练的并行数。

  10. min_alpha: 由于算法支持在迭代的过程中逐渐减小步长,min_alpha给出了最小的迭代步长值。随机梯度下降中每轮的迭代步长可以由iter,alpha, min_alpha一起得出。对于大语料,需要对alpha, min_alpha,iter一起调参,来选择合适的三个值。

  11. sg: 模型的选择,如果是0,则是CBOW模型,是1则是Skip-Gram模型,默认是0即CBOW模型。

  12. hs: 优化方法的选择,如果是0,则是Negative Sampling,是1的话并且负采样个数negative大于0, 则是Hierarchical Softmax。默认是0即Negative Sampling。

  13. negative:如果大于零,则会采用Negative Sampling,用于设置多少个noise words(一般是5-20)。

  14. cbow_mean: 仅用于CBOW在做投影的时候,为0,则采用上下文的词向量之和,为1则为上下文的词向量的平均值。默认值也是1,不推荐修改默认值。

  15. iter: 随机梯度下降法中迭代的最大次数,默认是5。对于大语料,可以增大这个值。

  16. batch_words:每一批传递给线程的单词的数量,默认为10000。

明确了调用和使用方法后,定义映射词向量的函数model_train(),使用语料库训练Word2Vec模型,将词语映射为向量。训练模型的代码如下所示:

In [2]:
def model_train(train_file_name, save_model_file):  # model_file_name为训练语料的路径,save_model为保存模型名
    from gensim.models import word2vec
    import gensim
    # 模型训练,生成词向量
    sentences = word2vec.Text8Corpus(train_file_name)  # 加载语料
    model = gensim.models.Word2Vec(sentences, size=200)  # 训练skip-gram模型; 默认window=5
    model.save(save_model_file)
    model.wv.save_word2vec_format(save_model_name + ".bin", binary=True)   # 以二进制类型保存模型以便重用

训练后的模型用普通方式和二进制方式进行保存,以便下次直接使用,避免每次训练耗费大量时间。下面对处理后的《倚天屠龙记》文档进行词向量训练,并生成相应的模型文件。

In [3]:
from gensim.models import word2vec
import os
import gensim

# if not os.path.exists(cut_file):    # 判断文件是否存在
cut_txt('倚天屠龙记.txt')  # 须注意文件必须先另存为utf-8编码格式

save_model_name = '倚天屠龙记.model'
if not os.path.exists(save_model_name):     # 判断文件是否存在
    model_train(cut_file, save_model_name)
else:
    print('此训练模型已经存在,不用再次训练')
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\Caesar\AppData\Local\Temp\jieba.cache
Loading model cost 1.019 seconds.
Prefix dict has been built successfully.

3.利用Word2Vec模型生成词向量并探究人物相关性

模型训练完毕后加载训练好的模型,导出所有词语的词向量。

In [7]:
# 加载已训练好的模型
model_1 = word2vec.Word2Vec.load(save_model_name)

vocab = model_1.wv.vocab  # 模型中的词库
word_vector = {}
for word in vocab:    
    word_vector[word] = model_1[word] # 映射到该词对应的向量
import pandas as pd
pd.DataFrame(word_vector).head()
Out[7]:
不可 静夜 沉沉 ... 九阴 白骨 古波斯 静照 纸片 武穆 军情 万人队 徐常 守宫砂
0 -0.179399 -0.239369 -0.100048 -0.354055 -0.219509 -0.079605 -0.054354 -0.022036 -0.044145 -0.175228 ... -0.025156 -0.020588 -0.039716 -0.024357 -0.017413 -0.026693 -0.026578 -0.021628 -0.037953 -0.017754
1 0.388041 0.149494 0.096600 0.441366 0.113548 0.060594 0.019533 0.046334 0.033604 0.100356 ... 0.026364 0.018618 0.015559 0.021146 0.005187 0.013487 0.010824 0.008332 0.030270 0.002708
2 0.479316 0.303818 0.171688 0.426212 0.255722 0.120239 0.071461 0.064669 0.069096 0.218663 ... 0.041289 0.027966 0.033523 0.054469 0.020531 0.040420 0.037480 0.027429 0.058909 0.022447
3 -0.363045 -0.245751 -0.163148 0.209628 -0.185878 -0.099030 -0.064770 -0.052787 -0.066232 -0.169680 ... -0.033929 -0.023879 -0.018365 -0.062978 -0.017280 -0.032694 -0.034622 -0.023896 -0.049598 -0.024925
4 -0.566146 0.030971 -0.005999 0.139892 -0.019838 -0.032340 -0.039049 -0.024204 -0.030332 -0.086931 ... -0.007605 -0.007805 -0.002492 -0.015998 -0.009881 -0.011994 -0.010737 -0.006734 -0.004823 -0.010665

5 rows × 10415 columns

生成词向量后,可以通过计算余弦相似度来衡量词向量$a=(x_1,x_2,...,x_n)^{\text T}$和$b=(y_1,...,y_n)^{\text T}$的相似程度,具体计算公式如下:

$$ cosine\_similarity(a,b)=\frac{\sum_{i=1}^nx_iy_i}{\sqrt{\sum_{i=1}^n x_i^2}×\sqrt{\sum_{i=1}^n y_i^2}} $$

直接调用similarity方法就可以计算词向量的余弦相似度,我们通过余弦相似度的值来衡量人物之间的相关性,首先输出男主角“张无忌”和女主角“赵敏”的人物相关性。另外,调用most_similar方法可以输出某个词前TopN个相关的词,我们再调用这个方法输出与男主角“张无忌”相关性最高的5个人物。

In [8]:
# 计算两个词的相似度/相关程度
y1 = model_1.similarity("赵敏", "张无忌")
print(u"赵敏和张无忌的人物相关性为:", y1)
print("-------------------------------\n")

# 计算某个词的相关词列表
y2 = model_1.most_similar("张无忌", topn=5)  # 5个最相关的
print(u"和张无忌最相关的人物有:\n")
for item in y2:
    print(item[0], item[1])
print("-------------------------------\n")
赵敏和张无忌的人物相关性为: 0.93758756
-------------------------------

和张无忌最相关的人物有:

张翠山 0.9590623378753662
周芷若 0.9504088163375854
赵敏 0.9375876188278198
殷素素 0.9216001629829407
谢逊 0.8992385864257812
-------------------------------

由结果可以看到,“赵敏”和“张无忌”的人物相关性大约为0.94,与“张无忌”相关性最高的5个人物分别是张翠山、周芷若、赵敏、殷素素和谢逊。

4.总结

本案例中将金庸先生的小说《倚天屠龙记》作为语料库,首先对语料库进行了预处理,包括分词、去除标点符号等;然后调用gensim库根据语料库训练Word2Vec模型,获得了每个词的词向量;最后利用余弦相似度度量词向量之间的相似度作为人物相关性的衡量,并以此探究了男主角“张无忌”和女主角“赵敏”的人物相关性以及与男主角“张无忌”相关性最高的5个人物。