任务
选一本小说,用gensim库训练它的word2vec词向量,进行初步探索。
分析
网上下载小说一般为txt格式,首先需要将它一行行的读入并进行分词处理。
(同时去除停用词)
word2vec需要输入sentences,也就是包含许多词语list的一个list。
关键步骤也就是将分词处理后的结果合适地存入list中。
实践
首先下载小说,这里下载了未完本的《剑来》作为素材训练,大小20几M。其次下载中文停用词表,网上有很多不同的中文停用词表可供选择。
import jieba
stop_path='cn_stopwords.txt' #停用词存储目录
novel_path = '456.txt' #小说存储目录
接下来需要将停用词表读入list存储:
stop_words = [] #创建一个List存储停用词
with open(stop_path, "r", encoding='utf8') as f:
line = f.readlines() #一段段读
for l in line:
stop_words.append(l.strip()) #l.strip()去掉空格
stop_words.append('------------') #每卷开头的-----也需要去掉
stop_words.append(' ') #把空格也加入停用词,分词有时候依然会保留空格
查看停用词长度:
len(stop_words) #返回结果共746个词
读取小说并进行分词:
novel_path = '456.txt' #小说目录
sentences=[] #一行行list组成的list
name = ['陈平安','齐静春','崔诚','宁姚','马苦玄','阮秀','刘羡阳','崔瀺','阮邛','裴钱','姜尚真','魏檗','稚圭','顾璨','老秀才','李槐','崔东山','道老二','白泽','礼圣','亚圣','文圣','阿良','陆沉','周米粒','陈暖树','陈景清','陈清都','魏晋','白也','陆台'] #主要人物名字
for k in name:
jieba.add_word(k) #把名字添加进字典,自带分词无法识别一些人名
with open(novel_path, "r", encoding='utf8') as f:
line = f.readlines()
for l in line:
l = l.strip() #去除空格
cstr=[] #存储一段话后分词的结果
if len(l) == 0:
continue
line_sen = jieba.cut(l, cut_all=False) #精确模式分词
for word in line_sen:
if word not in stop_words: #去除停用词
cstr.append(word)
if cstr == []:
continue #空的就不加入
sentences.append(cstr) #将一个list存进总list
每次读取一段话,通过jieba.cut方法分词,同时去除停用词。最终形成的sentences开头如下:
[[‘第一卷’, ‘笼中雀’, ‘第一章’, ‘惊蛰’],[‘二月’, ‘二’, ‘龙抬头’],…]
然后就可以开始训练word2vec模型:
import gensim
model = gensim.models.Word2Vec(sentences=sentences, size=100, window=5, min_count=5, sg=0)
参数用默认即可,size表示参数个数,window表示上下文滑动窗口数,min_count过滤低于5次的词,sg=0表示CBOW模型,1表示skip-gram模型。
model.wv.most_similar('陈平安')
wv.most_similar方法返回空间上最相似的词汇。
看看和陈平安意思最相近的都是什么词?
[('陆台', 0.7578437924385071),
('隋景澄', 0.7047308683395386),
('宁姚', 0.7027505040168762),
('齐景龙', 0.6674635410308838),
('马笃宜', 0.6537163853645325),
('崔东山', 0.6329615116119385),
('范大澈', 0.6114356517791748),
('曾掖', 0.6057554483413696),
('朱敛', 0.6050711870193481),
('崔诚', 0.6010798811912537)]
第一竟然是陆台!不是官配宁姚,连隋景澄都比她高!真没存在感啊宁姚。
from sklearn.manifold import TSNE
X_tsne = TSNE(learning_rate=200,perplexity=30).fit_transform(model.wv.vectors)
#TSNE方法把100维压缩成2维,方便在坐标轴上展现可视化结果
import plotly.express as px
fig = px.scatter(X_tsne, x=0, y=1,hover_name=model.wv.index2word)
fig.add_annotation(x=X_tsne[0, 0],y=X_tsne[0, 1],text=model.wv.index2word[0])
fig.show()
用tsne方法把所有的点在二维空间上的表示用plotly库的可交互作图实现。hover_name指定了悬停在其中一个点上时显示的标注,model.wv.index2word返回的是模型中的词汇。fig.add_annotation可以在点上方一定位置显示文字,这里我们有3万多个点,所以只添加了其中一个点的文字。效果如下:
我们可以在图上随意缩放一定区域查看具体情况,在有三万多个点又不想随机选取作图的情况下,plotly的可交互作图就非常好用。
这些点从左到右为酱菜、米饭、馄饨、酒菜、佐料、阳春面…等等,可以看到确实意思上相近,空间距离相近,都在一起呈现了。