使用Python探索四大名著【红楼梦】人物之间的关系,简直帅呆了 ...

打印 上一主题 下一主题

主题 552|帖子 552|积分 1656


 
 

《红楼梦》作为我国四大名著之一,古典小说的巅峰之作,粉丝量极其庞大,而红学也经久不衰。所以我们今天通过 Python 来探索下红楼梦里那千丝万缕的人物关系,话不多说,开始整活!
一、准备工作


  • 红楼梦txt格式电子书一份
  • 金陵十二钗+贾宝玉人物名称列表
  1. 宝玉 nr
  2. 黛玉 nr
  3. 宝钗 nr
  4. 湘云 nr
  5. 凤姐 nr
  6. 李纨 nr
  7. 元春 nr
  8. 迎春 nr
  9. 探春 nr
  10. 惜春 nr
  11. 妙玉 nr
  12. 巧姐 nr
  13. 秦氏 nr
复制代码
 
该分列表是为了做分词时使用,后面的 nr 就是人名的意思。
二、人物出镜次数

首先读取小说
  1. with open("红楼梦.txt", encoding="gb18030") as f:
  2.     honglou = f.read()
  3. # 更多视频教程、电子书、源码加君羊:279199867
复制代码
 
 
接下来进行出场次数数据整理
  1. honglou = honglou.replace("\n", " ")
  2. honglou_new = honglou.split(" ")
  3. renwu_list = ['宝玉', '黛玉', '宝钗', '湘云', '凤姐', '李纨', '元春', '迎春', '探春', '惜春', '妙玉', '巧姐', '秦氏']
  4. renwu = pd.DataFrame(data=renwu_list, columns=['姓名'])
  5. renwu['出现次数'] = renwu.apply(lambda x: len([k for k in honglou_new if x[u'姓名'] in k]), axis=1)
  6. renwu.to_csv('renwu.csv', index=False, sep=',')
  7. renwu.sort_values('出现次数', ascending=False, inplace=True)
  8. attr = renwu['姓名'][0:12]
  9. v1 = renwu['出现次数'][0:12]
复制代码
 
这样我们就得到了 attr 和 v1 两个数据,内容如下

 
 

下面就可以通过 pyecharts 来绘制柱状图了
  1. bar = (
  2.     Bar()
  3.     .add_xaxis(attr.tolist())
  4.     .add_yaxis("上镜次数", v1.tolist())
  5.     .set_global_opts(title_opts=opts.TitleOpts(title="红楼梦上镜13人"))
  6. )
  7. bar.render_notebook()
复制代码
 

 
 
三、人物关系

1、数据处理

我们先将读取到内存中的小说内容进行 jieba 分词处理
  1. import jieba
  2. jieba.load_userdict("renwu_forcut")
  3. renwu_data = pd.read_csv("renwu_forcut", header=-1)
  4. mylist = [k[0].split(" ")[0] for k in renwu_data.values.tolist()]
复制代码
 
通过 load_userdict 将我们上面自定义的词典加载到了 jieba 库中
分词处理
  1. tmpNames = []
  2. names = {}
  3. relationships = {}
  4. for h in honglou:
  5.     h.replace("贾妃", "元春")
  6.     h.replace("李宫裁", "李纨")
  7.     poss = pseg.cut(h)
  8.     tmpNames.append([])
  9.     for w in poss:
  10.         if w.flag != 'nr' or len(w.word) != 2 or w.word not in mylist:
  11.             continue
  12.         tmpNames[-1].append(w.word)
  13.         if names.get(w.word) is None:
  14.             names[w.word] = 0
  15.         relationships[w.word] = {}
  16.         names[w.word] += 1
复制代码
 
因为文中"贾妃", “元春”,“李宫裁”, “李纨” 等人物名字混用严重,所以这里做替换处理。
然后使用 jieba 库提供的 pseg 工具来做分词处理,会返回每个分词的词性。
之后做判断,只有符合要求且在我们提供的字典列表里的分词,才会保留。
一个人每出现一次,就会增加一,方便后面画关系图时,人物 node 大小的确定。
对于存在于我们自定义词典的人名,保存到一个临时变量当中 tmpNames
处理每个段落中的人物关系
  1. for name in tmpNames:
  2.         for name1 in name:
  3.             for name2 in name:
  4.                 if name1 == name2:
  5.                     continue
  6.                 if relationships[name1].get(name2) is None:
  7.                     relationships[name1][name2] = 1
  8.                 else:
  9.                     relationships[name1][name2] += 1
复制代码
 
对于出现在同一个段落中的人物,我们认为他们是关系紧密的,同时每出现一次,关系增加1 。
可以把相关信息保存到文件当中
  1. with open("relationship.csv", "w", encoding='utf-8') as f:
  2.         f.write("Source,Target,Weight\n")
  3.         for name, edges in relationships.items():
  4.             for v, w in edges.items():
  5.                 f.write(name + "," + v + "," + str(w) + "\n")
  6. with open("NameNode.csv", "w", encoding='utf-8') as f:
  7.     f.write("ID,Label,Weight\n")
  8.     for name, times in names.items():
  9.         f.write(name + "," + name + "," + str(times) + "\n")
复制代码
 
文件1:人物关系表,包含首先出现的人物、之后出现的人物和一同出现次数。
文件2:人物比重表,包含该人物总体出现次数,出现次数越多,认为所占比重越大。
2、数据分析

下面我们可以做一些简单的人物关系分析
这里我们还是使用 pyecharts 绘制图表
  1. def deal_graph():
  2.     relationship_data = pd.read_csv('relationship.csv')
  3.     namenode_data = pd.read_csv('NameNode.csv')
  4.     relationship_data_list = relationship_data.values.tolist()
  5.     namenode_data_list = namenode_data.values.tolist()
  6.     nodes = []
  7.     for node in namenode_data_list:
  8.         if node[0] == "宝玉":
  9.             node[2] = node[2]/3
  10.         nodes.append({"name": node[0], "symbolSize": node[2]/30})
  11.     links = []
  12.     for link in relationship_data_list:
  13.         links.append({"source": link[0], "target": link[1], "value": link[2]})
  14.     g = (
  15.         Graph()
  16.         .add("", nodes, links, repulsion=8000)
  17.         .set_global_opts(title_opts=opts.TitleOpts(title="红楼人物关系"))
  18.     )
  19.     return g
复制代码
 
首先把两个文件通过 pandas 读取到内存当中
对于“宝玉”,由于其占比过大,如果统一进行缩放,会导致其他人物的 node 过小,展示不美观,所以这里先做了一次缩放
最后我们得到的人物关系图如下

 
 

铁子们,今天的分享就到这, 如果感觉文章内容不错的话,记得关注+收藏让更多的人看到!
给大家分享一套视频,非常全面!
Python爬虫:代码总是学完就忘记?100个爬虫实战项目!让你沉迷学习丨学以致用丨下一个Python大神就是你!
 

  

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莫张周刘王

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表