用Python看金庸武侠.docx
- 文档编号:210494
- 上传时间:2023-04-28
- 格式:DOCX
- 页数:11
- 大小:23.06KB
用Python看金庸武侠.docx
《用Python看金庸武侠.docx》由会员分享,可在线阅读,更多相关《用Python看金庸武侠.docx(11页珍藏版)》请在冰点文库上搜索。
用Python看金庸武侠
用Python看金庸武侠
成为某个领域的高手究竟需要多少时间清华大学教授:
我们学校给不了你这些寒门如何出贵子金庸老爷子一共写了15部武侠小说,它们分别是:
《飞狐外传》(1960年)《雪山飞狐》(1959年)《连城诀》(1963年)《天龙八部》(1963年)《射雕英雄传》(1957年)《白马啸西风》(1961年)《鹿鼎记》(1969年)《笑傲江湖》(1967年)《书剑恩仇录》(1955年)《神雕侠侣》(1959年)《侠客行》(1965年)《倚天屠龙记》(1961年)《碧血剑》(1956年)《鸳鸯刀》(1961年)《越女剑》(1970年)我们现在就用Python来探索一下金庸小说中的武侠世界吧。
在处理小说之前,我们需要先做一些准备工作。
因为涉及中文字符,所以我们使用__future__中Python3的特性,将所有的字符串转为unicode。
from__future__importunicode_literals再来我们解决图像里中文字符显示的问题,Matplotlib虽然支持unicode编码,但是直接输出中文字体会出现问题。
inline出现上图的原因是它找不到合适的中文字体去显示中文,为此,我们可以去寻找一些支持中文的字体来进行设置。
Windows7及以上的系统中,字体位置为C:
/Windows/Fonts,例如:
宋体:
C:
/Windows/Fonts/simsum.ttcLinux系统可以通过fc-list命令查看已有的字体和相应的位置,例如:
/usr/share/fonts/truetype/osx-font-family/Songti.ttc:
SongtiTC,宋體\-繁,宋体\-繁:
style=Bold,粗體,粗体/usr/share/fonts/truetype/osx-font-family/DevanagariSangamMN.ttc:
DevanagariSangamMN,?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
:
style=Bold,粗體,Fed,Fett,Puolilihava,Gras,Grassetto,ボールド,?
?
?
Vet,Fet,Negrito,Жирный,?
?
?
?
?
粗体,Negrita/usr/share/fonts/truetype/osx-font-family/IowanOldStyle.ttc:
IowanOldStyle,IowanOldStyleBlack:
style=BlackItalic,Italic也可以从网上直接下载字体比如YaheiConsolas的字体YaHei.Consolas.1.11b.ttf。
找到了字体的位置,我们可以使用matplotlib.font_manager中的FontProperties导入字体:
font_xxx=FontProperties(fname='/usr/share/fonts/truetype/osx-font-family/Songti.ttc')font_xxx=FontProperties(fname='C:
//Windows//Fonts//simsum.ttc')
为了方便,我们不使用字体的绝对路径导入,而是将需要的字体放在程序对应的文件夹下:
YaHei.Consolas.1.11b.ttffrommatplotlib.font_managerimportFontPropertiesfont_yahei_consolas=FontProperties(fname='YaHei.Consolas.1.11b.ttf')在绘图的时候进行设置:
x=range(10)
plt.plot(x)
plt.title('中文',
fontproperties=font_yahei_consolas,
fontsize=14)
plt.show()我们从网上找到金庸小说的txt全文,放在novels文件夹中:
lsnovels
书剑恩仇录.txt天龙八部.txt碧血剑.txt越女剑.txt飞狐外传.txt侠客行.txt射雕英雄传.txt神雕侠侣.txt连城诀.txt鸳鸯刀.txt倚天屠龙记.txt白马啸西风.txt笑傲江湖.txt雪山飞狐.txt鹿鼎记.txt
接着,我们先找到金庸小说中所有出场的人物,放到names.txt文件中,其格式为:
小说1人物1人物2……小说2人物1人物2……小说3人物1人物2…………除此之外,另外有两个文本记录出场的门派(bangs.txt)和武功(kongfu.txt),用回车隔开。
withopen('names.txt')asf:
#去掉结尾的换行符data=[line.strip().decode('utf8')forlineinf.readlines()]novels=data[:
:
2]
names=data[1:
:
2]novel_names={k:
v.split()fork,vinzip(novels,names)}fornameinnovel_names['天龙八部'][:
20]:
printname刀白凤丁春秋马夫人马五德小翠于光豪巴天石不平道人邓百川风波恶甘宝宝公冶乾木婉清包不同天狼子太皇太后王语嫣乌老大无崖子云岛主
我们来看看人物在小说中的出场次数统计。
显然出场次数越多,自然主角光环越强,我们定义一个函数寻找小说中主角光环最强的几个人:
deffind_main_charecters(novel,num=10):
withopen('novels/{}.txt'.format(novel))asf:
data=f.read().decode('utf8')count=[]fornameinnovel_names[novel]:
count.append([name,data.count(name)])count.sort(key=lambdax:
x[1])_,ax=plt.subplots()numbers=[x[1]forxincount[-num:
]]names=[x[0]forxincount[-num:
]]ax.barh(range(num),numbers,color='red',align='center')ax.set_title(novel,
fontsize=14,
fontproperties=font_yahei_consolas)ax.set_yticks(range(num))ax.set_yticklabels(names,
fontsize=14,
fontproperties=font_yahei_consolas)天龙八部:
find_main_charecters('天龙八部')显然,就《天龙八部》来说,萧(乔)峰,段誉,虚竹这三兄弟的主角光环最强。
再看射雕三部曲:
find_main_charecters('射雕英雄传')
find_main_charecters('神雕侠侣')
find_main_charecters('倚天屠龙记')接下来,我们将使用一些机器学习的观点来处理这些小说。
Word2Vec是一款将词表征为实数值向量的高效工具,原理就不过多介绍了,感兴趣的可以自行搜索,gensim包提供了一个Python版的实现。
源代码地址:
gensim:
pipinstallgensim
安装完成之后,导入这个包:
importgensim虽然我们安装了gensim,但我们还不可以直接使用它来进行Word2Vec的操作,因为Word2Vec中的词默认是用空格分隔的,而中文小说显然不符合这个要求,为此,我们需要对中文进行分词。
一个比较好用的Python中文分词包叫做jieba(结巴)。
源代码地址:
jieba:
pipinstalljieba
导入:
importjiebajieba包具有一定的识别新词的能力,不过为了得到更准确的分词结果,我们可以将人名导入jieba库的字典,除此之外,我们还加入门派和武功的专有名词:
for_,namesinnovel_names.iteritems():
fornameinnames:
jieba.add_word(name)
withopen('kungfu.txt')asf:
kungfu_names=[line.decode('utf8').strip()
forlineinf.readlines()]
withopen('bangs.txt')asf:
bang_names=[line.decode('utf8').strip()
forlineinf.readlines()]fornameinkungfu_names:
jieba.add_word(name)fornameinbang_names:
jieba.add_word(name)我们按照行来处理文本,进行分词:
novels=['书剑恩仇录','天龙八部','碧血剑','越女剑','飞狐外传','侠客行','射雕英雄传','神雕侠侣','连城诀','鸳鸯刀','倚天屠龙记','白马啸西风','笑傲江湖','雪山飞狐','鹿鼎记']sentences=[]fornovelinnovels:
print'处理:
{}'.format(novel)withopen('novels/{}.txt'.format(novel))asf:
data=[line.decode('utf8').strip()
forlineinf.readlines()
ifline.decode('utf8').strip()]forlineindata:
words=list(jieba.cut(line))sentences.append(words)处理:
书剑恩仇录处理:
天龙八部处理:
碧血剑处理:
越女剑处理:
飞狐外传处理:
侠客行处理:
射雕英雄传处理:
神雕侠侣处理:
连城诀处理:
鸳鸯刀处理:
倚天屠龙记处理:
白马啸西风处理:
笑傲江湖处理:
雪山飞狐处理:
鹿鼎记
使用gensim中的默认参数进行训练:
model=gensim.models.Word2Vec(sentences,
size=100,
window=5,
min_count=5,
workers=4)有了模型之后,我们可以进行一些简单而有趣的测试。
首先看与乔峰相似的人:
fork,sinmodel.most_similar(positive=['乔峰','萧峰']):
printk,s段正淳0.839533925056慕容复0.800726354122虚竹0.796926677227童姥0.791711509228谢烟客0.787050366402游坦之0.786818385124余鱼同0.780444204807袁承志0.779631733894钟万仇0.759801149368贝海石0.756160736084
乱入了一只童姥,其他都是男性角色。
再看看与阿朱相似的人:
fork,sinmodel.most_similar(positive=['阿朱']):
printk,s钟灵0.789930582047阿紫0.77720785141方怡0.774438858032钟夫人0.767169654369香香公主0.763835728168王语嫣0.761606991291青青0.761157155037仪琳0.75483584404木婉清0.751208424568段誉0.745343744755
这回乱入了一只段誉。
除了人物,我们可以看看门派:
fork,sinmodel.most_similar(positive=['丐帮']):
printk,s长乐帮0.807791054249雪山派0.793763160706峨嵋派0.792181968689天地会0.789434850216门人0.785883545876红花会0.78480899334恒山派0.779587745667嵩山派0.77581256628全真教0.763592064381魔教0.746910750866fork,sinmodel.most_similar(positive=['降龙十八掌']):
printk,s打狗棒法0.89123404026空明拳0.890258312225太极拳0.884406626225一阳指0.874251723289心法0.874069094658八卦掌0.864349603653绝招0.864094853401乾坤大挪移0.858512759209六合拳0.852675139904拳法0.848574995995
在Word2Vec的模型里,有过“中国-北京=法国-巴黎”的例子,这里我们也可以找到这样的例子:
deffind_relationship(a,b,c):
'''
返回d
a与b的关系,跟c与d的关系一样
'''d,_=model.most_similar(positive=[c,b],negative=[a])[0]print'给定“{}”与“{}”,“{}”和“{}”有类似的关系'.format(a,b,c,d)find_relationship('段誉','段公子','乔峰')给定“段誉”与“段公子”,“乔峰”和“乔帮主”有类似的关系
类似的:
#情侣对
find_relationship('郭靖','黄蓉','杨过')
#岳父女婿
find_relationship('令狐冲','任我行','郭靖')
#非情侣
find_relationship('郭靖','华筝','杨过')给定“郭靖”与“黄蓉”,“杨过”和“小龙女”有类似的关系给定“令狐冲”与“任我行”,“郭靖”和“黄药师”有类似的关系给定“郭靖”与“华筝”,“杨过”和“绿萼”有类似的关系
以及,小宝你是有多爱康熙:
#韦小宝
find_relationship('杨过','小龙女','韦小宝')
find_relationship('令狐冲','盈盈','韦小宝')
find_relationship('张无忌','赵敏','韦小宝')给定“杨过”与“小龙女”,“韦小宝”和“康熙”有类似的关系给定“令狐冲”与“盈盈”,“韦小宝”和“康熙”有类似的关系给定“张无忌”与“赵敏”,“韦小宝”和“康熙”有类似的关系find_relationship('郭靖','降龙十八掌','黄蓉')
find_relationship('武当','张三丰','少林')
find_relationship('任我行','魔教','令狐冲')给定“郭靖”与“降龙十八掌”,“黄蓉”和“打狗棒法”有类似的关系给定“武当”与“张三丰”,“少林”和“灭绝师太”有类似的关系给定“任我行”与“魔教”,“令狐冲”和“恒山派”有类似的关系
之前我们对文本进行Word2Vec的结果,是将一个中文词组,映射到了一个向量空间,因此,我们可以利用这个向量表示的空间,对这些词进行聚类分析。
因为全部小说中的人物太多,我们考虑从单本小说进行入手,先把天龙八部中的人物的词向量拿出来:
all_names=[]word_vectors=Nonefornameinnovel_names['天龙八部']:
ifnameinmodel:
all_names.append(name)ifword_vectorsisNone:
word_vectors=model[name]else:
word_vectors=np.vstack((word_vectors,model[name]))all_names=np.array(all_names)聚类我们可以使用很多方法,这里我们先考虑Kmeans:
fromsklearn.clusterimportKMeans如果只分成3类,那么很明显地可以将众人分成主角,配角,跑龙套的三类:
N=3label=KMeans(N).fit(word_vectors).labels_forcinrange(N):
print'\n类别{}:
'.format(c+1)foridx,nameinenumerate(all_names[label==c]):
printname,ifidx%10==9:
printprint类别1:
刀白凤丁春秋马夫人巴天石邓百川风波恶公冶乾包不同乌老大云中鹤白世镜本因过彦之司马林玄慈玄寂玄难叶二娘左子穆李秋水全冠清阮星竹朱丹臣阿碧波罗星鸠摩智耶律洪基苏星河段延庆范骅赵钱孙哲罗星钟万仇秦红棉徐长老崔百泉萧远山褚万里慕容博谭婆薛慕华类别2:
马五德小翠不平道人甘宝宝天狼子太皇太后无崖子止清天山童姥本参本观本相出尘子冯阿三古笃诚兰剑平婆婆石嫂司空玄玄苦玄生玄痛耶律莫哥李春来李傀儡刘竹庄朴者和尚许卓诚竹剑阿洪阿胜陈孤雁来福儿努儿海宋长老苏辙吴长风辛双清严妈妈余婆婆岳老三张全祥单伯山单季山单小山单正段正明宗赞王子苟读华赫艮郁光标卓不凡范百龄哈大霸吴光胜梦姑神山上人神音室里姚伯当幽草龚光杰贾老者康广陵容子矩桑土公唐光雄奚长老诸保昆崔绿华符敏仪菊剑梅剑游骥游驹傅思归葛光佩缘根鲍千灵智光大师瑞婆婆端木元黎夫人谭公赫连铁树谭青摘星子慧方慧观慧净慧真穆贵妃吴领军易大彪类别3:
木婉清王语嫣乔峰萧峰阿朱阿紫段誉段正淳钟灵虚竹游坦之慕容复
我们把众龙套去掉,再聚一次:
N=4c=sp.stats.mode(label).moderemain_names=all_names[label!
=c]
remain_vectors=word_vectors[label!
=c]
remain_label=KMeans(N).fit(remain_vectors).labels_forcinrange(N):
print'\n类别{}:
'.format(c+1)foridx,nameinenumerate(remain_names[remain_label==c]):
printname,ifidx%10==9:
printprint类别1:
刀白凤马夫人风波恶包不同乌老大白世镜司马林叶二娘左子穆李秋水阮星竹阿碧苏星河赵钱孙钟万仇秦红棉崔百泉萧远山慕容博谭婆薛慕华类别2:
木婉清王语嫣阿朱阿紫段誉钟灵虚竹类别3:
丁春秋云中鹤乔峰萧峰鸠摩智段延庆段正淳游坦之慕容复类别4:
巴天石邓百川公冶乾本因过彦之玄慈玄寂玄难全冠清朱丹臣波罗星耶律洪基范骅哲罗星徐长老褚万里
可以看到,在类别2中,段家的儿女被聚在了一起,而萧峰则乱入了一群反派人士中。
换一本小说:
all_names=[]word_vectors=Nonefornameinnovel_names['倚天屠龙记']:
ifnameinmodel:
all_names.append(name)ifword_vectorsisNone:
word_vectors=model[name]else:
word_vectors=np.vstack((word_vectors,model[name]))all_names=np.array(all_names)这次采用层级聚类的方式,调用的是Scipy中层级聚类的包:
importscipy.cluster.hierarchyasschY=sch.linkage(word_vectors,method='ward')_,ax=plt.subplots(figsize=(10,40))Z=sch.dendrogram(Y,orientation='right')
idx=Z['leaves']ax.set_xticks([])
ax.set_yticklabels(all_names[idx],
fontproperties=font_yahei_consolas)
ax.set_frame_on(False)plt.show()红色聚类区的上半部分是与张教主直接相关的人物:
两个女人赵敏和周芷若;父母和义父。
而红色聚类区的下半部分主要是明教与武当中与张无忌相关的部分。
反派角色和一众龙套都被放在了下半区。
除了人物,我们还可以考虑对武功进行聚类分析:
all_names=[]word_vectors=Nonefornameinkungfu_names:
ifnameinmodel:
all_names.append(name)ifword_vectorsisNone:
word_vectors=model[name]else:
word_vectors=np.vstack((word_vectors,model[name]))
all_names=np.array(all_names)Y=sch.linkage(word_vectors,method='ward')_,ax=plt.subplots(figsize=(10,35))Z=sch.dendrogram(Y,orientation='right')idx=Z['leaves']ax.set_xticks([])ax.set_yticklabels(all_names[idx],
fontproperties=font_yahei_consolas)ax.set_frame_on(False)plt.show()反正我只知道下面绿色部分的武功,红色部分的好多都是第一次听说。
最后是门派的聚类:
all_names=[]word_vectors=Nonefornameinbang_names:
ifnameinmodel:
all_names.append(name)ifword_vectorsisNone:
word_vectors=model[name]else:
word_vectors=np.vstack((word_vectors,model[name]))
all_names=np.array(all_names)Y=sch.linkage(word_vectors,method='ward')_,ax=plt.su
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Python 看金庸 武侠