python基于共现的《红楼梦》人物关系图

作为中国古典四大名著,《红楼梦》的影响深远,至今家喻户晓。历来红学家们都在研究《红楼梦》。最近受python自然语言处理的影响,突然想用机器学习来实现红楼梦人物关系的大致情况。对于我这个从没读过《红楼梦》的人来说省去了很多时间,因为太长,真的读不来啊!那么,用python如何实现呢?

一.本文基于共现来提取人物关系,即一句话中两个人物出现,则加两个节点name1-name2,微weight=1,若以后在其他语句中再出现,则weight+1,以此类推,直到找到所有人物关系节点。

二。准备工作

需要提前在网上下载一个《红楼梦》人物表的txt,用来为以后选取人物节点做准备。格式如下:

黛玉,nr
宝钗,nr
贾演,nr
贾寅,nr
贾源,nr
贾法,nr
贾代化,nr
贾代善,nr
贾代儒,nr
贾代修,nr
贾敷,nr
贾敬,nr
贾赦,nr
贾政,nr
贾敏,nr
贾敕,nr
贾效,nr
贾敦,nr
贾珍,nr
贾琏,nr
贾珠,nr
贾母,nr
贾宝玉,nr
宝玉,nr
贾环,nr
贾瑞,nr
贾璜,nr
贾琮,nr
贾珩,nr
?,nr
贾珖,nr
贾琛,nr
贾琼,nr
贾璘,nr
贾元春,nr
贾迎春,nr
贾探春,nr
贾惜春,nr
贾蓉,nr
贾兰,nr
贾蔷,nr
贾菌,nr
贾芸,nr
贾芹,nr
贾萍,nr
贾菖,nr
贾菱,nr
贾蓁,nr
贾藻,nr
贾蘅,nr
贾芬,nr
贾芳,nr
贾芝,nr
贾荇,nr
贾芷,nr
贾葛,nr
贾巧姐,nr
巧姐儿,nr
史太君,nr
史鼐,nr
史鼎,nr
史湘云,nr
王子腾,nr
王子胜,nr
王夫人,nr
王仁,nr
王熙凤,nr
凤姐,nr
凤辣子,nr
薛姨妈,nr
薛蟠,nr
薛蝌,nr
薛宝钗,nr
薛宝琴,nr
林黛玉,nr
林妹妹,nr
邢夫人,nr
尤氏,nr
李纨,nr
秦可卿,nr
贾蓉之妻,nr
胡氏,nr
许氏,nr
香菱,nr
妙玉,nr
赵姨娘,nr
刘姥姥,nr
甄宝玉,nr
袭人,nr
媚人,nr
晴雯,nr
绮霰,nr
麝月,nr
檀云,nr
秋纹,nr
碧浪,nr
茜雪,nr
春燕,nr
坠儿,nr
四儿,nr
佳蕙,nr
抱琴,nr
司棋,nr
待书,nr
入画,nr
彩屏,nr
翠墨,nr
蝉姐,nr
莲花儿,nr
绣橘,nr
紫鹃,nr
雪雁,nr
春纤,nr
缕儿,nr
鸳鸯,nr
琥珀,nr
珍珠,nr
玻璃,nr
翡翠,nr
靛儿,nr
卐儿,nr
莺儿,nr
文杏,nr
平儿,nr
小红,nr
丰儿,nr
金钏,nr
玉钏,nr
绣鸾,nr
绣凤,nr
彩云,nr
彩霞,nr
素云,nr
同喜,nr
同贵,nr
翠缕,nr
宝珠,nr
瑞珠,nr
姣杏,nr
小螺,nr
善姐,nr
臻儿,nr
篆儿,nr
傻大姐,nr
小吉祥,nr
小鹊,nr
银碟,nr
炒豆儿,nr
小舍儿,nr
宝蟾,nr
茗烟,nr
焙茗,nr
焦大,nr
李贵,nr
锄药,nr
墨雨,nr
伴鹤,nr
扫花,nr
引泉,nr
挑芸,nr
双瑞,nr
双寿,nr
来旺,nr
兴儿,nr
王荣,nr
钱启,nr
张若锦,nr
赵亦华,nr
钱槐,nr
小玄儿,nr
隆儿,nr
昭儿,nr
喜儿,nr
住儿,nr
寿儿,nr
杏奴,nr
庆儿,nr
王信,nr
芳官,nr
龄官,nr
蕊官,nr
藕官,nr
豆官,nr
宝官,nr
文官,nr
茄官,nr
菂官,nr
艾官,nr
玉官,nr
葵官,nr
顽石,nr
茫茫大士,nr
渺渺真人,nr
空空道人,nr
甄士隐,nr
封氏,nr
小童,nr
神瑛侍者,nr
绛珠仙子,nr
警幻仙子,nr
贾雨村,nr
严老爷,nr
霍启,nr
封肃,nr
冷子兴,nr
林如海,nr
李嬷嬷,nr
王嬷嬷,nr
门子,nr
李守中,nr
冯渊,nr
拐子,nr
痴梦仙姑,nr
引愁金女,nr
种情大士,nr
度恨菩提,nr
王成,nr
刘氏,nr
板儿,nr
青儿,nr
周瑞,nr
周瑞家的,nr
智能,nr
余信,nr
余信家的,nr
秦钟,nr
赖二,nr
詹光,nr
戴良,nr
钱华,nr
单聘仁,nr
吴新登,nr
秦业,nr
胡氏,nr
金氏,nr
冯唐,nr
张友士,nr
戴权,nr
张材家的,nr
牛清,nr
牛继宗,nr
柳彪,nr
柳芳,nr
陈翼,nr
陈瑞文,nr
马魁,nr
马尚,nr
侯晓明,nr
侯孝康,nr
石光珠,nr
蒋子宁,nr
谢鲸,nr
戚建辉,nr
裘良,nr
冯紫英,nr
陈也俊,nr
卫若兰,nr
水溶,nr
二丫头,nr
净虚,nr
智善,nr
胡老爷,nr
金哥,nr
李公子,nr
云光,nr
夏守忠,nr
赖大,nr
赵嬷嬷,nr
吴天佑,nr
吴贵妃,nr
卜固修,nr
山子野,nr
林之孝,nr
程日兴,nr
昭容,nr
彩缤,nr
花母,nr
花自芳,nr
多官,nr
多浑虫,nr
多姑娘,nr
王嫂子,nr
周氏,nr
卜世仁,nr
银姐,nr
倪二,nr
王短腿,nr
林之孝家的,nr
方椿,nr
马道婆,nr
周姨娘,nr
胡斯来,nr
鲍太医,nr
王济仁,nr
蒋玉菡,nr
云儿,nr
张道士,nr
周奶娘,nr
傅试,nr
傅秋芳,nr
宋嬷嬷,nr
茗玉,nr
王君效,nr
赖大的母,nr
鲍二家的,nr
金彩,nr
金文翔,nr
嫣红,nr
柳湘莲,nr
赖尚荣,nr
邢岫烟,nr
邢忠,nr
李婶娘,nr
李纹,nr
李绮,nr
梅翰林,nr
胡君荣,nr
良儿,nr
乌进孝,nr
娄氏,nr
女先儿,nr
单大良,nr
赵国基,nr
单大娘,nr
祝妈,nr
田妈,nr
叶妈,nr
许氏,nr
何婆子,nr
小鸠儿,nr
夏婆子,nr
柳家的,nr
柳妈,nr
柳五儿,nr
秦显家的,nr
佩凤,nr
偕鸾,nr
尤二姐,nr
尤三姐,nr
尤老娘,nr
张华,nr
俞禄,nr
秋桐,nr
天文生,nr
喜鸾,nr
四姐,nr
潘又安,nr
朱大娘,nr
周太监,nr
小霞,nr
翠云,nr
来喜家的,nr
王善保家的,nr
张妈,nr
邢德全,nr
文花,nr
圆信,nr
智通,nr
孙绍祖,nr
夏金桂,nr
夏奶奶,nr
王一贴,nr

其中nr是我自动添加上去的,目的是利用jieba包判断词性。

三。代码

准备工作做好了,接下来就是写代码了,相对比较简单,具体如下:

#user/bin/env python
#-*- coding utf-8 -*-
# author:LiRuikun
#user/bin/env python
#-*- coding utf-8 -*-
# author:LiRuikun


import codecs
import jieba.posseg as pseg
import jieba

names = {}#  保存人物,键为人物名称,值为该人物在全文中出现的次数
relationships = {}#保存人物关系的有向边,键为有向边的起点,值为一个字典 edge edge 的键为有向边的终点,值是有向边的权值
lineNames = []# 缓存变量,保存对每一段分词得到当前段中出现的人物名称

jieba.load_userdict("names.txt")#加载人物表
with codecs.open("hlm.txt", 'r', 'utf8') 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:  # 如果某人物(w.word)不在人物字典中
                names[w.word] = 0
                relationships[w.word] = {}
            names[w.word] += 1

            # 输出人物出现次数统计结果
# for name, times in names.items():
#    print(name, times)

# 对于 lineNames 中每一行,我们为该行中出现的所有人物两两相连。如果两个人物之间尚未有边建立,则将新建的边权值设为 1# 否则将已存在的边的权值加 1。这种方法将产生很多的冗余边,这些冗余边将在最后处理。
for 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

                # 由于分词的不准确会出现很多不是人名的人名,从而导致出现很多冗余边,
                # 为此可设置阈值为10,即当边出现10次以上则认为不是冗余

with codecs.open("People_node.txt", "w", "utf8") as f:
    f.write("ID Label Weight\r\n")
    for name, times in names.items():
        if times > 10:
            f.write(name + " " + name + " " + str(times) + "\r\n")



with codecs.open("People_edge.txt", "w", "utf8") as f:
    f.write("Source Target Weight\r\n")
    for name, edges in relationships.items():
        for v, w in edges.items():
            if w > 10:
                f.write(name + " " + v + " " + str(w) + "\r\n")

运行完毕之后,打开关系图的txt表,发现结果是这个样子的:

Source Target Weight
甄士隐 贾政道 16
甄士隐 冯紫英 12
贾雨村 王夫人 12
贾雨村 宝玉 31
贾雨村 黛玉 20
贾雨村 老太太 15
青埂峰 宝玉 31
青埂峰 宝钗 15
青埂峰 王夫人 31
青埂峰 和尚 17
那僧道 士隐 15
那僧 士隐 25
那僧 宝玉 13
美玉 宝玉 12
花柳 宝玉 14
那僧笑 宝玉 13
明白 士隐 34
明白 雨村 16
明白 凤姐 285
明白 周瑞家 59
明白 宝玉 741
明白 贾蓉 25
明白 明白人 11
明白 贾琏 134
明白 林黛玉 64

只贴取了部分数据,发现有很多非人名的词如‘明白’,‘祖宗’等,应将其过滤。此时可再次最照names.txt来筛选非人名的词。筛选过程代码如下:

f=open('People_edge.txt','r',encoding='utf-8')
f2=open('names.txt','r',encoding='utf-8').read()
lines=f.readlines()


A=[]
for line in lines:
    A.append([])
    m=line.strip('\n').split(' ')
    for x in m:
        A[-1].append(x)
for items in A:
    if items[0]and items[1] not in f2:
        del(items)

f.close()

print(A)

最后去掉非人名的词后,基本就是人名了。然后将筛选过后的人物关系存入result.txt中。

四。最后一步便是引入gephi软件了,它可以画出给定的输入带关系表的数据表的图,具体我就不介绍了。gehpi软件界面如下:

python基于共现的《红楼梦》人物关系图_第1张图片

非常简单易用,接下来将导入我们刚才的result.csv了。

通过一系列的设置,便得到我们想要的人物关系图了

python基于共现的《红楼梦》人物关系图_第2张图片

画的比较粗糙,不过大致得到我们想要的了。


你可能感兴趣的:(python基于共现的《红楼梦》人物关系图)