word2vec需要去标点吗_word2vec学习笔记(应用篇)(金庸武侠)

写在前面

本来是想写“实战篇”的,感觉实验语料库不大,就算是一个"应用篇"吧。选取了中文语料,主要简单介绍jieba分词的使用,以及Gemsim模块中Word2Vec的使用。word2vec的原理可以参考之前的文章:华夏狼崽:word2vec学习笔记(原理篇)​zhuanlan.zhihu.com

一、语料介绍

一直比较喜欢金庸的武侠小说,所以语料选取了金庸的十五部小说(精校版),最初的项目中只训练了一部《射雕英雄传》,内容太少不够爽,可以分析的关系也不多,所以一次性训练了十五部小说,看是否能得到不同小说之间一些人物、门派、武功的关系。

二、文本预处理

要训练词向量,首先就要得到词,原始的数据都是完整的文本、句子,怎样得到词语呢?这里用到一个很好用的模块:jieba。jieba模块是一个python中文分词模块,可以将输入的句子分为词语,有三种分词方式:精准模式,全模式和搜索引擎模式。安装方法和更细节的使用方式这里不做介绍,可以参考jieba的官方github:fxsjy/jieba

1. 导入jieba模块和其他相关模块并加载文件路径

import os

import jieba

import warnings

warnings.filterwarnings('ignore')

novel_path = "E:/Learn/WORD2VEC/金庸小说精校版/"

data_path = "E:/Learn/WORD2VEC/"

novel_path为小说原始文本路径,data_path为其他一些文件的路径(下文一一介绍)。

2. 过滤标点以及停用词

在分词中,标点符号是我们不需要的。还有一类词,是训练词向量时不需要的,这些词单独出现没有什么具体意义,比如"的","各位","什么"等等,这一类词称为停用词(stop word)。停用词表的选择需要根据实际应用环境调整,这里我的停用词表下载了网上比较通用的中文语料停用词表,根据词向量训练结果做了一点点调整,添加了几个在武侠小说中容易出现而我并不想得到它的词向量的词,比如"说道"等等。

由于下载的停用词表中包含了标点符号,所以这里可以把标点当作停用词合并一起处理。加载停用词表:

stop_words_file = open(data_path + "stop_words.txt", 'r')

stop_words = list()

for line in stop_words_file.readlines():

line = line.strip() # 去掉每行末尾的换行符

stop_words.append(line)

stop_words_file.close()

print(len(stop_words))

print(stop_words[300:320])

看一下一共几个停用词,抽一些出来随便看看有哪些词:

1903

['乘势', '乘机', '乘胜', '乘虚', '乘隙', '九', '也', '也好', '也就是说', '也是', '也罢', '了', '了解', '争取', '二', '二来', '二话不说', '二话没说', '于', '于是']

停用词表加载完毕,后面只需判断分出的词是否在表里即可,如果在表里则舍弃不要。

3. 添加自定义词汇

最开始的实验中,我是直接分词的,但是发现,很多想要的词汇都没能正确的分出来,包括一些重要人物的名称,一些重要的武功等,是因为这些词汇都是武侠小说这种特定环境下的专有名词,jieba的词汇表中并没有收录,所以我整理了三份txt文本,分别记录了武侠小说中的人物名称、武功名称和门派名称,参考来源:金庸网-金庸数据库。

将人名添加到词汇表中:

people_names_file = open(data_path + "金庸小说全人物.txt", 'r')

people_names = list()

for line in people_names_file.readlines():

line = line.strip() # 去掉每行末尾的换行符

jieba.add_word(line)

people_names.append(line)

stop_words_file.close()

print(len(people_names))

添加的人名数量:

1237

类似的,导入了389个武功名称和97个门派名称。

4. 分词

分词本来我以为是没有什么的,直接用精确模式逐本逐行的分就好了。实际操作时遇到了一点小问题。先看一下文件名:

novel_names = list(os.listdir(novel_path))

novel_names

输出:

['书剑恩仇录.txt',

'侠客行.txt',

'倚天屠龙记.txt',

'天龙八部.txt',

'射雕英雄传.txt',

'白马啸西风.txt',

'碧血剑.txt',

'神雕侠侣.txt',

'笑傲江湖.txt',

'越女剑.txt',

'连城诀.txt',

'雪山飞狐.txt',

'飞狐外传.txt',

'鸳鸯刀.txt',

'鹿鼎记.txt']

逐本逐行的分词发现结果中有很多类似这样的词:

['黄蓉道', '郭靖叫', '黄蓉喜', '黄蓉思', '谢逊怒']

很多人名没能够分割出来,和后面的一个字练成了一个新的词语。这主要是因为中文语言太灵活了,的确难以完美分割每个词。如果数量不多的话,我也就接受这个结果了。简单统计了一下,以"黄蓉"为例,一共出现两千多次,有超出五分之一是分错的,这个数量就比较大了,需要考虑解决的方法。再统计观察了一下,发现只有两个字的人名会出现这种情况,三个字的和四个字的名字都能很好的分割开,这样就容易解决了。

我的解决策略是,对分出来的词,判断它的前两个字组成的新词是否在全部人名列表中,如果存在,则直接用新词替换它加入分词表。这样的方法很容易上面的问题,但是有一个缺点,就是如果存在一个人的名字的前两个字,恰好也是另外一个人的名字,这样就直接会直接把第二个人名字记下导致分错了,举例:有两人分别名为"王毛毛"和"王毛",当分词结果分出"王毛毛",就会因为它的前两个字存在于人名表中,就会把这个词改成"王毛",这其实是错误的。这种情况其实是可以避免的,只需要再加一个规则:如果整个名字是正确的人名的话,就优先使用原始分词结果。这个规则是可以的,但是我并没有使用,原因是在金庸先生的武侠小说中,给人物起名基本没有这种情况,起的名字差距都挺远的,主角们名称更是不会和其他的有这种重叠情况。好像只有《倚天屠龙记》中"张三丰"和《侠客行》里的一个小人物"张三"出现这个问题,我选择删掉"张三",我并不想分析这个人物:)

代码如下:

seg_novel = []

for novel_name in novel_names:

novel = open(novel_path + novel_name, 'r', encoding='utf-8-sig')

print("Waiting for{}...".format(novel_name))

line = novel.readline()

forward_rows = len(seg_novel)

while line:

line_1 = line.strip()

outstr = ''

line_seg = jieba.cut(line_1, cut_all=False)

for word in line_seg:

if word not in stop_words:

if word != '\t':

if word[:2] in people_names:

word = word[:2]

outstr += word

outstr += " "

if len(str(outstr.strip())) != 0:

seg_novel.append(str(outstr.strip()).split())

line = novel.readline()

print("{}finished,with{}Row".format(novel_name, (len(seg_novel) - forward_rows)))

print("-" * 40)

print("-" * 40)

print("-" * 40)

print("All finished,with{}Row".format(len(seg_novel)))

可以看到每一本书分词后的行数和总行数:

Waiting for 书剑恩仇录.txt...

书剑恩仇录.txt finished,with 3561 Row

----------------------------------------

Waiting for 侠客行.txt...

侠客行.txt finished,with 3513 Row

----------------------------------------

Waiting for 倚天屠龙记.txt...

倚天屠龙记.txt finished,with 7918 Row

----------------------------------------

Waiting for 天龙八部.txt...

天龙八部.txt finished,with 10947 Row

----------------------------------------

Waiting for 射雕英雄传.txt...

射雕英雄传.txt finished,with 7130 Row

----------------------------------------

Waiting for 白马啸西风.txt...

白马啸西风.txt finished,with 597 Row

----------------------------------------

Waiting for 碧血剑.txt...

碧血剑.txt finished,with 3786 Row

----------------------------------------

Waiting for 神雕侠侣.txt...

神雕侠侣.txt finished,with 6998 Row

----------------------------------------

Waiting for 笑傲江湖.txt...

笑傲江湖.txt finished,with 8550 Row

----------------------------------------

Waiting for 越女剑.txt...

越女剑.txt finished,with 196 Row

----------------------------------------

Waiting for 连城诀.txt...

连城诀.txt finished,with 2207 Row

----------------------------------------

Waiting for 雪山飞狐.txt...

雪山飞狐.txt finished,with 1096 Row

----------------------------------------

Waiting for 飞狐外传.txt...

飞狐外传.txt finished,with 3776 Row

----------------------------------------

Waiting for 鸳鸯刀.txt...

鸳鸯刀.txt finished,with 211 Row

----------------------------------------

Waiting for 鹿鼎记.txt...

鹿鼎记.txt finished,with 11158 Row

----------------------------------------

----------------------------------------

----------------------------------------

All finished,with 71644 Row

随便取几行出来看看:

['郭靖', '黄蓉', '完颜洪烈', '做', '爹爹', '语气', '间', '亲热', '相互', '一眼', '郭靖', '气恼', '难受', '恨不得', '揪住', '问个', '明白']

['黄蓉', '郭靖', '边道', '喝得', '酒儿', '偏', '两人', '溜', '出阁', '子', '来到', '后园', '黄蓉', '晃动', '火折', '点燃', '柴房中', '柴草', '四下', '放', '起火']

['一日', '中', '洪七公', '心', '早已', '御厨', '之内', '好容易', '挨到', '时分', '郭靖', '负', '洪七公', '四人', '上屋', '径往', '大内', '皇宫', '高出', '民居', '屋瓦', '金光灿烂', '极易', '辨认', '不多时', '四人', '已悄', '没声', '跃进', '宫墙']

['完颜洪烈', '悄声', '所说', '耳目众多', '饮酒', '三人', '转过', '话题', '说些', '景物', '见闻', '风土人情']

嗯,不错,是我想要的效果,通过一个嵌套列表存储,每一句为列表中一个元素,每一句又由分好的词构成一个列表,这也是word2vec训练时需要输入的格式。

三、训练词向量

这里用的是Gemsim模块中Word2Vec。Gemsim模块是一个据说功能很强大的NLP处理模块,我只尝试了Word2Vec函数,以后有需要的话学习一下其他部分。训练代码如下:

import gensim.models as w2v

model = w2v.Word2Vec(sentences=seg_novel, size=200, window=5, min_count=5, sg=0)

model.save(data_path + 'all_CBOW.model') # 保存模型

说一下Word2Vec中的几个参数,sentences是输入的语料,即分词得到的嵌套列表,可以通过LineSentence或Text8Corpus函数构造。size即是训练得到的词向量的维数。window为滑窗大小,也就是训练词与上下文词最远的距离。min_count是指过滤掉一些低词频的词。sg为选择CBOW模型还是skip-gram模型,0为CBOW模型,1为skip-gram模型,默认为CBOW模型(实际发现CBOW和skip-gram模式得到的结果差距还是比较大的,具体可以看下文对比)。还有一些其他参数,不一一列出,可以参考官方文档:gensim: topic modelling for humans​radimrehurek.com

1. CBOW

参数都选取默认(CBOW),训练得到词向量模型。接下来做一些简单有趣的测试。

首先是用模型测试一些词的相似度(实则根据词向量计算余弦相似度)。

print(model.similarity('张无忌', '周芷若'))

print(model.similarity('张无忌', '赵敏'))

看一下张无忌和周芷若、赵敏哪个相似度更高呢:

0.70147747

0.74265605

好吧,还是和赵敏比较好。

看一下和张无忌最接近的五个词:

print(model.most_similar("张无忌", topn=5))

[('令狐冲', 0.8610879182815552),

('虚竹', 0.8390334844589233),

('黑白子', 0.8079050779342651),

('张翠山', 0.8067573308944702),

('苗人凤', 0.7919591665267944)]

诶?除了张翠山之外,其他的几个人怎么关联的呢?实际大概是因为令狐冲、虚竹等也是其他小说中数一数二重要的人物吧。

看一下和峨嵋派最接近的五个词:

print(model.most_similar("峨嵋派", topn=5))

[('华山派', 0.9490149021148682),

('昆仑派', 0.9471687078475952),

('嵩山派', 0.9393842220306396),

('本派', 0.9321860074996948),

('雪山派', 0.9311256408691406)]

除了"本派"乱入,其他也都是一些门派。

韦小宝关系最乱,看下和哪个老婆最好:

print(model.similarity('韦小宝', '阿珂'))

print(model.similarity('韦小宝', '双儿'))

print(model.similarity('韦小宝', '建宁公主'))

print(model.similarity('韦小宝', '苏荃'))

print(model.similarity('韦小宝', '沐剑屏'))

print(model.similarity('韦小宝', '曾柔'))

print(model.similarity('韦小宝', '方怡'))

0.46550432

0.51736045

0.46725014

0.45597148

0.5102725

0.36221734

0.50045687

双儿第一,沐剑屏其次,没看过鹿鼎记不做分析。

看一下和韦小宝最接近的十个词:

print(model.most_similar("韦小宝", topn=10))

[('康熙', 0.6945387125015259),

('公主', 0.6921814680099487),

('乾隆', 0.6888490915298462),

('太后', 0.6246222257614136),

('苏菲亚', 0.605838418006897),

('周总镖', 0.6015807390213013),

('祖千秋', 0.6013493537902832),

('小桂子', 0.5954452753067017),

('陈家洛', 0.5947461128234863),

('徐天宏', 0.5941584706306458)]

没想到7个老婆都没进入前十,反而编外老婆苏菲亚排名那么高。。不过韦小宝和康熙皇帝的关系是真的近呀。

除此之外,还可以用以下函数寻找对应关系:类似于李白之与唐代,等于曹雪芹之于清代。

def find_relation(a, b, c):

d, _ = model.most_similar(positive=[c, b], negative=[a])[0]

print (c,d)

首先就想找一下,杨过之与小龙女等于张无忌之于谁:

print(find_relation("杨过","小龙女","张无忌"))

张无忌 赵敏

~~~~~~~~这个结果还是找的比较准的,心疼周芷若一秒。但是有一些就不准了,乱入了,比如:

print(find_relation("杨过","小龙女","郭靖))

郭靖 石清

。。不止这里有乱入,在测试一些人的最接近词时,也有很多挺难解释的,可能他们相似的维度并不容易观察的到吧。接下来用skip-gram尝试,是不是同样的效果呢?

2. skip-gram

只需把sg参数设置为1即可,参数也选用默认参数。

杨过之与小龙女等于张无忌之于谁:

print(find_relation("杨过","小龙女","张无忌"))

张无忌 周芷若

。。。逆风翻盘?那赶紧看看其他的结果:

print(find_relation("杨过","小龙女","郭靖"))

郭靖 蓉儿

print(find_relation("杨过","小龙女","黄蓉"))

黄蓉 靖哥哥

这个就有点秀了呀,不仅能找对人,找到的还是昵称。。。

和张无忌最接近的五个词:

print(model.most_similar("张无忌", topn=5))

[('周芷若', 0.6134092211723328),

('赵敏', 0.5959696769714355),

('小昭', 0.5360002517700195),

('杨逍', 0.5234625935554504),

('波斯', 0.49604594707489014)]

这下就没有其他时代乱入的人了,而且也都是比较好解释的通的

还可以找找这样的关系:

print(find_relation("杨过","小龙女","乔峰"))

乔峰 阿朱

print(find_relation("杨过","小龙女","段誉"))

段誉 王语嫣

print(find_relation("杨过","小龙女","段正淳"))

段正淳 刀白凤

print(find_relation("武当派","张三丰","峨嵋派"))

峨嵋派 周芷若

print(find_relation("武当派","张三丰","天地会"))

天地会 陈近南

乔峰阿朱这个就没什么好说的了,段氏父子的异性关系圈一直比较复杂。。从词向量的角度看,段誉还是对神仙姊姊钟情的,段正淳还是对正室妻子有更多的情感的。

武当派之于张三丰----峨嵋派不应该是"灭绝师太"嘛?哈哈,好吧,周芷若毕竟也是做过峨嵋掌门的,也算解释的通吧。不止是在同一部小说中可以对应这种关系,通过《倚天屠龙记》中的武当派掌门张三丰也可以找到《鹿鼎记》中天地会总舵主陈近南。

最后再看一个原著中比较神秘的人:

print(model.most_similar("王重阳", topn=10))

[('林朝英', 0.8663322925567627),

('宝典', 0.8595889210700989),

('研习', 0.8348122835159302),

('创制', 0.8294848799705505),

('先天功', 0.8276116251945496),

('医术', 0.827604353427887),

('精研', 0.8269264101982117),

('神通', 0.8256270885467529),

('剑宗', 0.8248381614685059),

('功诀', 0.8226447701454163)]

这个结果还是蛮满意的,王重阳作为一个武学奇才,五绝之首,世称"天下第一",与"创制","研习","精研"一类词相近,然而排在第一的,却还是对他因爱生恨的林朝英。

写在后面:

有意思的测试还有很多,就不一一叙述了。乱入的结果也不少,优化分词或者调整参数可能有更好的结果。

总之从结果看来CBOW模型,更注重文章整体的关联,很多相似度高的词跨越了多个时代,多本小说,而skip-gram模型更加注重局部,相似度高的词基本集中在同一本小说中。查阅了一些文章后,的确说CBOW模型在语料库较大时效果较好,skip-gram模型在语料库较小时候效果比较好。可能十五本小说语料库的确比较小吧,所以skip-gram模型的测试结果的可解释性更强点。

这也只是从训练出的词向量做的最直接的测试,后续还可以用聚类,分类等其他算法进行其他更有意思的测试。相关的代码和文件上传在github上,感兴趣的话可以自己尝试一下:wolfkin-hth/novels​github.com

学习路漫漫,狼崽在路上~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/287947.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ArcGIS实验教程——实验四:数字化属性数据的采集

ArcGIS实验视频教程合集:《ArcGIS实验教程从入门到精通》(附配套实验数据) 目录 一、实验内容 二、实验目的 三、实验数据 四、实验过程 【实验描述】 属性数据是GIS空格数据的重要组成部分。属性数据采集的基本操作由于地理实体(如建筑物) 位于地块之内成者与地…

[图] DevOps:提速从研发到交付流程

你的产品要让用户等多久?制定需求、排期开发、部署调试……这些流程都再跑一遍?传统产品发布流程长,多分支、环境不一、人工操作导致容易出错。面对这些传统发布难题,DevOps才是正确的出路。

php基础教程 第四步 学习运算符

在前面的章节中,以及了解了一些运算法,接下来再讲解一些常规运算法。 加运算法,用来使左右两边的值或表达式进行加法计算。例如有一个变量$a,一个变量$b,它们的值都为9,$a$b为99等于10.。输出使用echo&…

JavaScript基础学习(七)—BOM

BOM(Browser Object Model): 浏览器对象模型。提供了独立于内容而与浏览器窗口交互的对象,BOM主要用于管理窗口和窗口之间的通讯。 一、Navigator对象 navigator对象通常用于获取浏览器和操作系统的信息。 navigator对象是window对象的属性,中文是&…

ArcGIS实验教程——实验五:空间数据编辑

ArcGIS实验视频教程合集:《ArcGIS实验教程从入门到精通》(附配套实验数据) 【实验描述】 利用ArcGIS进行数字化之后,需要对采集的空间数据进行编辑,包括图形编辑和属性编辑。常用的编辑工具有:编辑折点、延续要素、打断线、连接线、自动完成面、剪切面,整形面等等。 一…

Spring初识

从上学期开始决心开始学习Spring,自己总是利用不好时间,到处瞎忙,结果浪费了好多时间。想着利用暑假的时间,专心看会儿书。最初我在Spring官网下载jar包的时候,忙会儿了半天愣是没找到下载的链接,瞬间觉得学…

batchsize和数据量设置比例_Keras - GPU ID 和显存占用设定步骤

初步尝试 Keras (基于 Tensorflow 后端)深度框架时, 发现其对于 GPU 的使用比较神奇, 默认竟然是全部占满显存, 1080Ti 跑个小分类问题, 就一下子满了. 而且是服务器上的两张 1080Ti.服务器上的多张 GPU 都占满, 有点浪费性能.因此, 需要类似于 Caffe 等框架的可以设定 GPU ID …

Blazor University (17)使用 RenderFragments 模板化组件

原文链接:https://blazor-university.com/templating-components-with-renderfragements/使用 RenderFragments 模板化组件源代码[1]到目前为止,我们已经创建了基于参数生成 100% 渲染输出的组件,但组件并不总是那么简单。有时我们需要创建将…

OpenGL® ES 3.0 Programming Guide - Book Website

OpenGL ES 3.0 Programming Guide - Book Website http://opengles-book.com sample codes in GitHub: https://github.com/danginsburg/opengles3-book/

ArcGIS实验教程——实验六:空间数据格式转换

ArcGIS实验视频教程合集:《ArcGIS实验教程从入门到精通》(附配套实验数据) 【实验描述】 空间数据从一个GIS平台跨到另一个GIS,必须经过格式转换,才能实现数据信息共享。本实验主要讲述空间数据矢栅互转、CAD(DWG)数据和Shapefile数据互转、栅格数据与ASCII文件之间的转换…

php基础教程 第五步 逻辑控制

逻辑判断 在开发项目时,竟然会出现逻辑控制。例如当用户输入“hello”时你需要自动回复“hello 欢迎”,当用户设置的定时时间到达时,你需要提醒用户时间已经结束;再举个例子,在玩网络游戏时,用户控制的角色…

在春意盎然的季节里初识GIT

Git 与 SVN 区别 GIT不仅仅是个版本控制系统,它也是个内容管理系统(CMS),工作管理系统等。 如果你是一个具有使用SVN背景的人,你需要做一定的思想转换,来适应GIT提供的一些概念和特征。 Git 与 SVN 区别点: 1、GIT是分布式的&…

WinForm混合Blazor(下)

有时,为了省事,我们也可以把窗体的控件注入到ServiceCollection中,在razor中订阅事件,这样就省了中间的桥梁,直接用控件当桥梁,下面以一个Button和Timer为例,来展示使用方式。本例是把Button和T…

ArcGIS实验教程——实验七:矢量数据空间校正(Spatial Adjustment)

ArcGIS实验视频教程合集:《ArcGIS实验教程从入门到精通》(附配套实验数据) 【实验描述】 本系列实验教程实验二讲述了栅格数据的数字化之前必须进行的操作--地理配准(地理配配准完整操作步骤),栅格地理配准和矢量空间校正都属于几何校正的内容,关于空间校正、地理配准、…

数据结构之冒泡排序

1 冒泡排序 冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来 算法过程如下: 比较相邻的元素。如果第一个比第二个大,就交换他们两个。 对每一对相邻元素作同样的工作,从开始第一…

博图程序需要手动同步_贴吧求助帖博图实例单按钮控制灯的程序

接上一期在贴吧看见的求助帖(上图看得见水印),因为没人回复,发帖的楼主好像删除了帖子。结果我抽时间用博图15.1,S71200做了一个,希望给需要帮助的新人能够起到作用,感觉有用的话可以关注一下我的公众号低压电工&#…

操作系统,,,也考完了【流坑】

操作系统博大精深岂是区区2学分能容?学习了一些机制和理论模型之后课外还是要继续学习转载于:https://www.cnblogs.com/learn-to-rock/p/5447750.html

php基础教程 第六步 学习数组以及条件判断switch补充

条件语句 switch 在上一节的学习中&#xff0c;学习了php的条件语句if。在php编程中进行条件判断还可以使用switch语句。switch语句语法如下&#xff1a; <?php switch (值或表达式) { case 值等于值1:当值等于值1时要执行的代码break; case 值等于值2:当值等于值2时要执…

ArcGIS实验教程——实验八:矢量数据拼接

ArcGIS实验视频教程合集:《ArcGIS实验教程从入门到精通》(附配套实验数据) 【实验描述】 数字化工作都是分工完成的,那么数字化完成之后,怎样将各部分数字化的成果拼接成一个完整的矢量数据呢?本实验针对线状和面状矢量数据,讲解矢量化数据拼接的常用方法:合并(merge)…

iOS 类库列表

1. LinqToObjectiveC #import "NSArrayLinqExtensions.h" 它为NSArray添加了许多方法&#xff0c;能让你用流式API来转换、排序、分组和过滤其中的数据。转载于:https://www.cnblogs.com/SimonGao/p/4747065.html