提起中国武侠小说,金庸先生是绕不开的名字,十余年间以汪洋恣肆的想象力,写下15部作品。可用"飞雪连天射白鹿,笑书神侠倚碧鸳"来形容。
这些作品分别是《飞狐外传》(1960年)、《雪山飞狐》(1959年)、《连城诀》(1963年)、《天龙八部》(1963年)、《射雕英雄传》(1957年)、《白马啸西风》(1961年)、《鹿鼎记》(1969年)、《笑傲江湖》(1967年)、《书剑恩仇录》(1955年)、《神雕侠侣》(1959年)、《侠客行》(1965年)、《倚天屠龙记》(1961年)、《碧血剑》(1956年)《鸳鸯刀》(1961年)、《越女剑》(短篇小说)(1970年)。
数据获取
编写简单的爬虫程序获取金庸15本小说,并写入本地txt文件中。爬虫函数不在此展示。
文本处理
分别将小说的人物(names)、功夫(kungfu)、派别(bangs)写入txt文件中,并与小说放在同一个文件夹中。
file='D:/CuteHand/jr_novels/names.txt' #本地文件夹,根据需要修改#可以使用os模块的添加路径with open(file) as f: # 去掉结尾的换行符 data = [line.strip() for line in f.readlines()]novels = data[::2]names = data[1::2]novel_names = {k: v.split() for k, v in zip(novels, names)}
金庸小说充满恩怨情仇,其中,《倚天屠龙记》中张无忌一生遇到很多女人,如赵敏、周芷若、小昭、蛛儿、朱九真、杨不悔等,到底谁是女主角呢?我们来看下这几位美女在小说中分别出现的次数。
file='D:/CuteHand/jr_novels/倚天屠龙记.txt'with open(file) as f: data = f.read()Actress=['赵敏','周芷若','小昭','蛛儿', '朱九真','杨不悔']for name in Actress: print("%s"% name,data.count(name))赵敏 1240周芷若 819小昭 352蛛儿 231朱九真 141杨不悔 190
将这几位美女在小说中出现的次数进行可视化,可以更直观地看出哪位才是张无忌的归属:
#可视化,重点在于学习使用matplotlib库画图#导入需要的包 import numpy as npimport scipy as spimport matplotlib.pyplot as plt%matplotlib inline#画图正常显示中文from pylab import mpl mpl.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 mpl.rcParams['axes.unicode_minus']=False # 用来正常显示负号actress_data = {'赵敏':1240,'周芷若': 819, '小昭': 352,'蛛儿': 231, '朱九真': 141,'杨不悔': 190} for a, b in actress_data.items(): plt.text(a, b + 0.05, '%.0f' % b, ha='center', va='bottom', fontsize=12) #ha 文字指定在柱体中间, #va指定文字位置 #fontsize指定文字体大小# 设置X轴Y轴数据,两者都可以是list或者tuplex_axis = tuple(actress_data.keys())y_axis = tuple(actress_data.values())plt.bar(x_axis, y_axis, color='rgbyck') # 如果不指定color,所有的柱体都会是一个颜色#b: blue g: green r: red c: cyan#m: magenta y: yellow k: black w: whiteplt.xlabel("女角名") # 指定x轴描述信息plt.ylabel("小说中出现次数") # 指定y轴描述信息plt.title("谁是女主角?") # 指定图表描述信息plt.ylim(0, 1400) # 指定Y轴的高度plt.show()
众所周知,张无忌最终和赵敏在一起了,而与周芷若之间很是坎坷…;小昭挺喜欢的角色,可惜被不可抗拒的外力给分开了;蛛儿,暂且说是女方单恋吧;朱九真只是过客,不过也算是张无忌情窦初开喜欢的一个;杨不悔只能说是玩伴。
文本挖掘
接下来,通过分析小说人物的出场次数来判断小说的主要人物。
#继续挖掘下倚天屠龙记里面人物出现次数排名namelist=[name.strip() for name in novel_names['倚天屠龙记']]namelist=''.join(namelist)namelist=namelist.split('、')count = []num=10 #统计前10名for name in namelist: count.append([name, data.count(name)])count.sort(key=lambda x: x[1])_, ax = plt.subplots()numbers = [x[1] for x in count[-num:]]names = [x[0] for x in count[-num:]]ax.barh(range(num), numbers, align='center')ax.set_title('倚天屠龙记', fontsize=14)ax.set_yticks(range(num))ax.set_yticklabels(names, fontsize=10)plt.show()
网上收集了下金庸小说的功夫和门派种类,分别写入kungfu.txt和bangs.txt中,其中武功246种,门派120个。
#加入功夫和门派数据file='D:/CuteHand/jr_novels/'with open(file+"kungfu.txt") as f: kungfu_names = [line.strip() for line in f.readlines()]with open(file+"bangs.txt") as f: bang_names = [line.strip() for line in f.readlines()]#编写文本挖掘可视化函数#寻找小说出现最多的十大人物def find_main_characters(novel): file='D:/CuteHand/jr_novels/' with open(file+'names.txt') as f: df = [line.strip() for line in f.readlines()] novels = df[::2] names = df[1::2] novel_names = {k: v.split() for k, v in zip(novels, names)} with open(file+'{}.txt'.format(novel)) as f: data = f.read() count = [] namelist=[name.strip() for name in novel_names[novel]] namelist=''.join(namelist) namelist=namelist.split('、') for name in namelist: count.append([name, data.count(name)]) count.sort(key=lambda x: x[1]) _, ax = plt.subplots() num=10 numbers = [x[1] for x in count[-num:]] names = [x[0] for x in count[-num:]] ax.barh(range(num), numbers, align='center') ax.set_title(novel+"出现最多的十大人物", fontsize=16) ax.set_yticks(range(num)) ax.set_yticklabels(names, fontsize=14)#寻找小说出现最多的十大武功def kungfu(novel): file='D:/CuteHand/jr_novels/' with open(file+'{}.txt'.format(novel)) as f: df = f.read() namelist=kungfu_names count = [] num=10 #统计前10名 for name in namelist: count.append([name, df.count(name)]) count.sort(key=lambda x: x[1]) _, ax = plt.subplots() numbers = [x[1] for x in count[-num:]] names = [x[0] for x in count[-num:]] ax.barh(range(num), numbers, align='center') ax.set_title(novel+"出现最多的十大武功", fontsize=16) ax.set_yticks(range(num)) ax.set_yticklabels(names, fontsize=14)#寻找小说出现最多的十大门派def bang(novel): file='D:/CuteHand/jr_novels/' with open(file+'{}.txt'.format(novel)) as f: df = f.read() namelist=bang_names count = [] num=10 #统计前10名 for name in namelist: count.append([name, df.count(name)]) count.sort(key=lambda x: x[1]) _, ax = plt.subplots() numbers = [x[1] for x in count[-num:]] names = [x[0] for x in count[-num:]] ax.barh(range(num), numbers, align='center') ax.set_title(novel+"出现最多的十大门派", fontsize=16) ax.set_yticks(range(num)) ax.set_yticklabels(names, fontsize=14)#将三个函数合成一个主函数def main(novel): find_main_characters(novel) bang(novel) kungfu(novel)main('倚天屠龙记')
main('天龙八部')
main('神雕侠侣')
main('笑傲江湖')
寻找人物关系
使用gensim和jieba包对文本做进一步挖掘,寻找人物之间的关系。一般要先安装相应的包,只要在Anaconda Prompt上输入pip install gensim和pip install jieba进行安装即可。
import gensimimport warningswarnings.filterwarnings(action='ignore', category=UserWarning,module='gensim')warnings.filterwarnings(action='ignore', category=FutureWarning,module='gensim')import jiebafor _, names in novel_names.items(): for name in names: jieba.add_word(name)file='D:/CuteHand/jr_novels/'with open(file+"kungfu.txt") as f: kungfu_names = [line.strip() for line in f.readlines()]with open(file+"bangs.txt") as f: bang_names = [line.strip() for line in f.readlines()]for name in kungfu_names: jieba.add_word(name)for name in bang_names: jieba.add_word(name)books = ['天龙八部','鹿鼎记','神雕侠侣','笑傲江湖', '碧血剑','倚天屠龙记','飞狐外传','书剑恩仇录', '侠客行','鸳鸯刀','白马啸西风','雪山飞狐']sentences = []for novel in books: print ("处理:{}".format(novel)) with open(file+'{}.txt'.format(novel)) as f: data = [line.strip() for line in f.readlines() if line.strip()] for line in data: words = list(jieba.cut(line)) sentences.append(words)model = gensim.models.Word2Vec(sentences, size=100,window=5, min_count=5, workers=4)
首先,来看下《倚天屠龙记》里张无忌与哪位女角的关系最紧密。
Actress=['赵敏','周芷若','小昭','蛛儿', '朱九真','杨不悔']for a in Actress: print("张无忌与%s的相关度" % a,model. wv.similarity('张无忌',a))
结果如下:
张无忌与赵敏的相关度 0.7922112张无忌与周芷若的相关度 0.7983359张无忌与小昭的相关度 0.60103273张无忌与蛛儿的相关度 0.7526051张无忌与朱九真的相关度 0.5569755张无忌与杨不悔的相关度 0.5574214
从文本挖掘上看,张无忌似乎与周芷若“关系”更加紧密。不过,周芷若与赵敏的相关度非常接近。
其次,运用12部小说(其中,射雕英雄传、越女剑和连城诀可能存在非法字符,读不出来)交叉判断人物之间的关系。
def find_relationship(a, b, c): """ 返回 d a与b的关系,跟c与d的关系一样 """ d, _ = model.wv.most_similar([c, b], [a])[0] print ("给定“{}”与“{}”,“{}”和“{}”有类似的关系". format(a, b, c, d))find_relationship('小龙女','杨过' ,'黄蓉')
输出结果(Interesting!):
给定“小龙女”与“杨过”,“黄蓉”和“郭襄”有类似的关系
词云
通过对小说文本中出现频率较高的“关键词”予以视觉上的突出,形成“关键词云层”或“关键词渲染”,过滤掉大量的文本信息,可以试着通过关键词来自行串起故事的梗概和判断人物的关系。
#引入需要的包import jiebaimport jieba.analyseimport numpy as npimport codecsimport pandas as pdfrom wordcloud import WordCloud, STOPWORDS, ImageColorGenerator#读入《倚天屠龙记》文本内容text=codecs.open('D:/CuteHand/jr_novels/倚天屠龙记.txt', 'rb','gbk').read()tags=jieba.analyse.extract_tags(text,topK=100, withWeight=True)tf=dict((a[0],a[1]) for a in tags)#识别中文文本wc=WordCloud(font_path='C:WindowsFontsSTZHONGS.TTF')wc=wc.generate_from_frequencies(tf)plt.figure(num=None,figsize=(12,10),facecolor='w',edgecolor='k')plt.imshow(wc)plt.axis('off')plt.show()
生成特定形状的词云
backgroud_Image = plt.imread('D:/CuteHand/jr_novels/地图.jpg')#可以自己找适合的图片做背景,最后是背景白色wc = WordCloud( background_color='white', # 设置背景颜色 mask=backgroud_Image, # 设置背景图片 font_path='C:WindowsFontsSTZHONGS.TTF', # 若是有中文的话,这句代码必须添加 max_words=2000, # 设置最大现实的字数 stopwords=STOPWORDS,# 设置停用词 max_font_size=150,# 设置字体最大值 random_state=30 # 设置有多少种随机生成状态,即有多少种配色方案)wc.generate_from_frequencies(tf)#img_colors = ImageColorGenerator(backgroud_Image)#字体颜色为背景图片的颜色#wc.recolor(color_func=img_colors)plt.figure(num=None,figsize(12,10), facecolor='w',edgecolor='k')plt.imshow(wc)# 是否显示x轴、y轴下标plt.axis('off')plt.show()
将上述过程包装成函数,方便批量处理
def jr_cloud(novel,file): import jieba import jieba.analyse import numpy as np import codecs import pandas as pd from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator text=codecs.open(file+'{}.txt'.format(novel), 'rb','gbk').read() tags=jieba.analyse.extract_tags(text,topK=50,withWeight=True) tf=dict((a[0],a[1]) for a in tags) wc=WordCloud(font_path='c:windowsontssimsun.ttc', background_color='white') wc=wc.generate_from_frequencies(tf) plt.figure(num=None,figsize=(12,10), facecolor='w',edgecolor='k') plt.title(novel,fontsize=18) plt.imshow(wc) plt.axis('off') plt.show()file='D:/CuteHand/jr_novels/'novels = ['天龙八部','鹿鼎记','神雕侠侣','笑傲江湖', '碧血剑','倚天屠龙记','飞狐外传','书剑恩仇录', '侠客行','鸳鸯刀','白马啸西风','雪山飞狐']jr_cloud(novels[0],file)
#鹿鼎记词云jr_cloud(novels[1],file)
#笑傲江湖词云jr_cloud(novels[3],file)
人物关系网络分析
最后运用网络分析法,将小说中的人物关系用图形展示出来。
import networkx as nximport matplotlib.pyplot as pltimport jiebaimport codecsimport jieba.posseg as psegnames = {} # 姓名字典relationships = {} # 关系字典lineNames = [] # 每段内人物关系# count namesjieba.load_userdict(novel_names['倚天屠龙记']) with codecs.open("D:/CuteHand/jr_novels/ 倚天屠龙记.txt", "r") as f: for line in f.readlines(): poss = pseg.cut(line) # 分词并返回该词词性 lineNames.append([]) # 为新读入的一段添加人物名称列表 for w in poss: if w.flag != "nr" or len(w.word) < 2: continue # 当分词长度小于2或该词词性不为nr时认为该词不为人名 lineNames[-1].append(w.word) # 为当前段的环境增加一个人物 if names.get(w.word) is None: names[w.word] = 0 relationships[w.word] = {} names[w.word] += 1 # 该人物出现次数加 1# explore relationshipsfor line in lineNames: # 对于每一段 for name1 in line: for name2 in line: # 每段中的任意两个人 if name1 == name2: continue if relationships[name1].get(name2) is None: # 若两人尚未同时出现则新建项 relationships[name1][name2]= 1 else: relationships[name1][name2] = relationships[name1][name2]+ 1 # 两人共同出现次数加 1with codecs.open("D:/CuteHand/jr_novels/person_edge.txt", "a+", "utf-8") as f: for name, edges in relationships.items(): for v, w in edges.items(): if w >500: f.write(name + " " + v + " " + str(w) + "")a = []f = open('D:/CuteHand/jr_novels/person_edge.txt', 'r',encoding='utf-8')line = f.readline()while line: a.append(line.split()) #保存文件是以空格分离的 line = f.readline()f.close()#画图G = nx.Graph()G.add_weighted_edges_from(a)nx.draw(G,with_labels=True,font_size=9, node_size=800,node_color='r')plt.show()
最终呈现:
用户评论
这个游戏主题真是太棒了!我是金庸笔迷,一直想知道剧情背后那些隐藏的故事。
有15位网友表示赞同!
终于能深入了解主角们的内心想法,看清他们之间的纠葛。
有19位网友表示赞同!
期待游戏能够捕捉到金庸小说原著的细腻情感描写和刀光剑影。
有20位网友表示赞同!
文本挖掘这个玩法听起来很有趣!希望能有互动式的剧情和解谜环节。
有6位网友表示赞同!
如果能通过游戏体验不同角色的角度,那该有多震撼!
有18位网友表示赞同!
希望游戏能够呈现出金庸小说中侠义精神的魅力。
有16位网友表示赞同!
我喜欢探索隐藏故事的感觉,感觉这次会玩很久很沉浸。
有12位网友表示赞同!
看金庸小说的时候一直觉得人物关系复杂,现在能用游戏的方式深入了解真是太棒了!
有5位网友表示赞同!
期待游戏的画面和音乐能够营造出侠客情深的氛围。
有9位网友表示赞同!
我以前也玩过一些文本冒险游戏,这个主题真的很吸引人。
有17位网友表示赞同!
希望游戏能够照顾到不同玩家的喜好,提供多种玩法选择。
有6位网友表示赞同!
感觉可以结合AR技术的互动体验会更有趣!
有5位网友表示赞同!
期待这款游戏的推出,一定会成为金庸爱好者的必玩之作。
有15位网友表示赞同!
这个题材非常独特,我相信游戏肯定会带来不一样的体验!
有20位网友表示赞同!
希望能看到更多不同金庸小说的人物和故事的融入。
有14位网友表示赞同!
真替那些喜欢解谜的小伙伴开心!相信文本挖掘的游戏机制会很考思辨能力。
有18位网友表示赞同!
期待游戏能够在剧情上和玩法上都给我惊喜!
有17位网友表示赞同!
希望以后还能开发其他基于文学作品的文本冒险游戏,这真是个好主意!
有14位网友表示赞同!
金庸小说的主题非常适合做成游戏,这个题材有很大的潜力。
有7位网友表示赞同!