1. 程式人生 > >python基於共現的《紅樓夢》人物關係圖

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軟體介面如下:


非常簡單易用,接下來將匯入我們剛才的result.csv了。

通過一系列的設定,便得到我們想要的人物關係圖了


畫的比較粗糙,不過大致得到我們想要的了。