中国体彩网唯一官网
首頁 > Python教程 > 正文

趣味玩轉——用python分析《三國演義》中的社交網絡

轉載 2019-04-04 17:37:15 0 1087
第六期線上培訓班
一直以來對自然語言處理和社交網絡分析都很感興趣,前者能幫助我們從文本中獲得很多發現,而后者能夠讓我們對人們和各個事物之間普遍存在的網絡般的聯系有更多認識。當二者結合,又會有怎樣的魔力呢?作為一個三國迷,我就有了這樣的想法:能不能用文本處理的方法,得到《三國演義》中的人物社交網絡,再進行分析呢?python中有很多好工具能夠幫助我實踐我好奇的想法,現在就開始動手吧。

1554370510824156.png

準備工作

獲得《三國演義》的文本

chapters = get_sanguo()                 # 文本列表,每個元素為一章的文本print(chapters[0][:106])第一回 宴桃園豪杰三結義 斬黃巾英雄首立功滾滾長江東逝水,浪花淘盡英雄。是非成敗轉頭空。青山依舊在,幾度夕陽紅。白發漁樵江渚上,慣看秋月春風。一壺濁酒喜相逢。古今多少事,都付笑談中

《三國演義》并不是很容易處理的文本,它接近古文,我們會面對古人的字號等一系列別名。比如電腦怎么知道“玄德”指的就是“劉備”呢?那就要我們給它一些知識。我們人通過學習知道“玄德”是劉備的字,電腦也可以用類似的方法完成這個概念的連接。我們需要告訴電腦,“劉備”是實體(類似于一個對象的標準名),而“玄德”則是“劉備”的一個指稱,告訴的方式,就是提供電腦一個知識庫。

entity_mention_dict, entity_type_dict = get_sanguo_entity_dict()
print("劉備的指稱有:",entity_mention_dict["劉備"]

劉備的指稱有: [ 劉備 , 劉玄德 , 玄德 , 使君 ]

除了人的實體和指稱以外,我們也能夠包括三國勢力等別的類型的指稱,比如“蜀”又可以叫“蜀漢”,所以知識庫里還可以包括實體的類型信息來加以區分。

print("劉備的類型為",entity_type_dict["劉備"])
print("蜀的類型為",entity_type_dict["蜀"])
print("蜀的指稱有",entity_mention_dict["蜀"])

劉備的類型為 人名
蜀的類型為 勢力
蜀的指稱有 [ 蜀 , 蜀漢 ]

有了這些知識,理論上我們就可以編程聯系起實體的各個綽號啦。不過若是要從頭做起的話,其中還會有不少的工作量。而HarvestText[1]是一個封裝了這些步驟的文本處理庫,可以幫助我們輕松完成這個任務。

ht = HarvestText()ht.add_entities(entity_mention_dict, entity_type_dict)      # 加載模型print(ht.seg("誓畢,拜玄德為兄,關羽次之,張飛為弟。",standard_name=True))[ 誓畢 , , , 拜 , 劉備 , 為兄 , , , 關羽 , 次之 , , , 張飛 , 為弟 , 。 ]

社交網絡建立

成功地把指稱統一到標準的實體名以后,我們就可以著手挖掘三國的社交網絡了。具體的建立方式是利用鄰近共現關系。每當一對實體在兩句話內同時出現,就給它們加一條邊。那么建立網絡的整個流程就如同下圖所示:

1554368780391261.png

我們可以使用HarvestText提供的函數直接完成這個流程,讓我們先在第一章的小文本上實踐一下:

# 準備工作
doc = chapters[0].replace("操","曹操")                                  # 由于有時使用縮寫,這里做一個微調
ch1_sentences = ht.cut_sentences(doc)     # 分句
doc_ch01 = [ch1_sentences[i]+ch1_sentences[i+1] for i in range(len(ch1_sentences)-1)]  #獲得所有的二連句
ht.set_linking_strategy("freq")

# 建立網絡
G = ht.build_entity_graph(doc_ch01, used_types=["人名"])              # 對所有人物建立網絡,即社交網絡

# 挑選主要人物畫圖
important_nodes = [node for node in G.nodes if G.degree[node]>=5]
G_sub = G.subgraph(important_nodes).copy()
draw_graph(G_sub,alpha=0.5,node_scale=30,figsize=(6,4))

1554368884749985.png

他們之間具體有什么關系呢?我們可以利用文本摘要得到本章的具體內容:

stopwords = get_baidu_stopwords()    #過濾停用詞以提高質量for i,doc in enumerate(ht.get_summary(doc_ch01, topK=3, stopwords=stopwords)): print(i,doc)玄德見皇甫嵩、朱儁,具道盧植之意。嵩曰:“張梁、張寶勢窮力乏,必投廣宗去依張角。時張角賊眾十五萬,植兵五萬,相拒于廣宗,未見勝負。植謂玄德曰:“我今圍賊在此,賊弟張梁、張寶在潁川,與皇甫嵩、朱儁對壘。次日,于桃園中,備下烏牛白馬祭禮等項,三人焚香再拜而說誓曰:“念劉備、關羽、張飛,雖然異姓,既結為兄弟,則同心協力,

本章的主要內容,看來就是劉關張桃園三結義,并且共抗黃巾賊的故事。

三國全網絡繪制

有了小范圍實踐的基礎,我們就可以用同樣的方法,整合每個章節的內容,畫出一張橫跨三國各代的大圖。

G_chapters = []

整個社交網絡有1290個人那么多,還有上萬條邊!那么我們要把它畫出來幾乎是不可能的,那么我們就挑選其中的關鍵人物來畫出一個子集吧。

important_nodes = [node for node in G_global.nodes if G_global.degree[node]>=30]

用pyecharts進行可視化

from pyecharts import Graph

博客上不能顯示交互式圖表,這里就給出截圖:顯示了劉備的鄰接結點

1554369154362436.png

整個網絡錯綜復雜,背后是三國故事中無數的南征北伐、爾虞我詐。不過有了計算機的強大算力,我們依然可以從中梳理出某些關鍵線索,比如:

人物排名-重要性

對這個問題,我們可以用網絡中的排序算法解決。PageRank就是這樣的一個典型方法,它本來是搜索引擎利用網站之間的聯系對搜索結果進行排序的方法,不過對人物之間的聯系也是同理。讓我們獲得最重要的20大人物:

page_ranks = pd.Series(nx.algorithms.pagerank(G_global)).sort_values()
page_ranks.tail(20).plot(kind="barh")
plt.show()

1554369316678173.png

結果的確和上面的排序有所不同,我們看到劉備、曹操、孫權、袁紹等主公都名列前茅。而另一個有趣的發現是,司馬懿、司馬昭、司馬師父子三人同樣榜上有名,而曹氏的其他后裔則不見其名,可見司馬氏之權傾朝野。司馬氏之心,似乎就這樣被大數據揭示了出來!

社群發現

人物關系有親疏遠近,因此往往會形成一些集團。社交網絡分析里的社區發現算法就能夠讓我們發現這些集團,讓我使用community庫[2]中的提供的算法來揭示這些關系吧。

import community                                    # python-louvainpartition = community.best_partition(G_main)         # Louvain算法劃分社區comm_dict = defaultdict(list)for person in partition:   comm_dict[partition[person]].append(person)

在下面3個社區里,我們看到的主要是魏蜀吳三國重臣們。(只有一些小“問題”,有趣的是,電腦并不知道他們的所屬勢力,只是使用算法。)

draw_community(2)
ommunity 2: 張遼 曹仁 夏侯惇 徐晃 曹洪 夏侯淵 張郃 許褚 樂進 李典 于禁 荀彧 劉曄 郭嘉 滿寵 程昱 荀攸 呂虔 典韋 文聘 董昭 毛玠
draw_community(4)
community 4: 曹操 諸葛亮 劉備 關羽 趙云 張飛 馬超 黃忠 許昌 孟達[魏] 孫乾
曹安民 劉璋 關平 龐德 法正 伊籍 張魯 劉封 龐統 孟獲 嚴顏 馬良 簡雍 蔡瑁 
陶謙 孔融 劉琮[劉表子] 劉望之 夏侯楙 周倉 陳登
draw_community(3)
community 3: 孫權 孫策 周瑜 陸遜 呂蒙 丁奉 周泰 程普 韓當 徐盛 張昭[吳] 馬相 黃蓋[吳] 潘璋 甘寧 魯肅 凌統 太史慈 諸葛瑾 韓吳郡 蔣欽 黃祖 闞澤 朱桓 陳武 呂范
draw_community(0)
community 0: 袁紹 呂布 劉表 袁術 董卓 李傕 賈詡 審配 孫堅 郭汜 陳宮 馬騰 
袁尚 韓遂 公孫瓚 高順 許攸[袁紹] 臧霸 沮授 郭圖 顏良 楊奉 張繡 袁譚 董承 
文丑 何進 張邈[魏] 袁熙

還有一些其他社區。比如在這里,我們看到三國前期,孫堅、袁紹、董卓等主公們群雄逐鹿,好不熱鬧。

draw_community(1)
community 1: 司馬懿 魏延 姜維 張翼 馬岱 廖化 吳懿 司馬昭 關興 吳班 王平 
鄧芝 鄧艾 張苞[蜀] 馬忠[吳] 費祎 譙周 馬謖 曹真 曹丕 李恢 黃權 鐘會 蔣琬
司馬師 劉巴[蜀] 張嶷 楊洪 許靖 費詩 李嚴 郭淮 曹休 樊建 秦宓 夏侯霸 楊儀
 高翔 張南[魏] 華歆 曹爽 郤正 許允[魏] 王朗[司徒] 董厥 杜瓊 霍峻 胡濟 賈充
  彭羕 吳蘭 諸葛誕 雷銅 孫綝 卓膺 費觀 杜義 閻晏 盛勃 劉敏 劉琰 杜祺 上官雝 
  丁咸 爨習 樊岐 曹芳 周群

這個社區是三國后期的主要人物了。這個網絡背后的故事,是司馬氏兩代三人打敗姜維率領的蜀漢群雄,又掃除了曹魏內部的曹家勢力,終于登上權力的頂峰。

動態網絡

研究社交網絡隨時間的變化,是個很有意思的任務。而《三國演義》大致按照時間線敘述,且有著極長的時間跨度,順著故事線往下走,社交網絡會發生什么樣的變化呢?

這里,我取10章的文本作為跨度,每5章記錄一次當前跨度中的社交網絡,就相當于留下一張快照,把這些快照連接起來,我們就能夠看到一個社交網絡變化的動畫。快照還是用networkx得到,而制作動畫,我們可以用moviepy。

江山代有才人出,讓我們看看在故事發展的各個階段,都是哪一群人活躍在舞臺中央呢?

import moviepy.editor as mpy
from moviepy.video.io.bindings import mplfig_to_npimage
width, step = 10,5
range0 = range(0,len(G_chapters)-width+1,step)
numFrame, fps = len(range0), 1
duration = numFrame/fps
pos_global = nx.spring_layout(G_main)

def make_frame_mpl(t):
   i = step*int(t*fps)
   G_part = nx.Graph()
   for G0 in G_chapters[i:i+width]:
       for (u,v) in G0.edges:
           if G_part.has_edge(u,v):
               G_part[u][v]["weight"] += G0[u][v]["weight"]
           else:
               G_part.add_edge(u,v,weight=G0[u][v]["weight"])
   largest_comp = max(nx.connected_components(G_part), key=len)
   used_nodes = set(largest_comp) & set(G_main.nodes)
   G = G_part.subgraph(used_nodes)
   fig = plt.figure(figsize=(12,8),dpi=100)
   nx.draw_networkx_nodes(G,pos_global,node_size=[G.degree[x]*10 for x in G.nodes])
#     nx.draw_networkx_edges(G,pos_global)
   nx.draw_networkx_labels(G,pos_global)
   plt.xlim([-1,1])
   plt.ylim([-1,1])
   plt.axis("off")
   plt.title(f"第{i+1}到第{i+width+1}章的社交網絡")
   return mplfig_to_npimage(fig)
animation = mpy.VideoClip(make_frame_mpl, duration=duration)

animation.write_gif("./images/三國社交網絡變化.gif", fps=fps)

美觀起見,動畫中省略了網絡中的邊。

1554369822998830.gif

隨著時間的變化,曾經站在歷史舞臺中央的人們也漸漸地會漸漸離開,讓人不禁唏噓感嘆。正如《三國演義》開篇所言:

古今多少事,都付笑談中。

今日,小輩利用python做的一番笑談也就到此結束吧……

【推薦課程:Python視頻教程

以上就是趣味玩轉——用python分析《三國演義》中的社交網絡的詳細內容,更多請關注php中文網其它相關文章!

php中文網最新課程二維碼
  • 相關標簽:Python
  • 本文轉載于:Python爬蟲與數據挖掘,如有侵犯,請聯系刪除
  • 相關文章


  • Python 爬取張國榮最火的 8 首歌,60000 評論看完淚奔!
  • Python爬蟲基礎之網頁組成解析
  • Python列表推導式 你也能用好
  • 非常適合菜鳥練手的3道趣味Python題
  • 分享7道Python開發工程師面試題
  • 趣味玩轉——用python分析《三國演義》中的社交網絡
  • 網友評論

    文明上網理性發言,請遵守 新聞評論服務協議

    我要評論
    獨孤九賤(5)_ThinkPHP5視頻教程

    獨孤九賤(5)_ThinkPHP5視頻教程

    ThinkPHP是國內最流行的中文PHP開發框架,也是您Web項目的最佳選擇。《php.cn獨孤九賤(5)-ThinkPHP5視頻教程》課程以ThinkPHP5最新版本為例,從最基本的框架常識開始,將...

    獨孤九賤(4)_PHP視頻教程

    獨孤九賤(4)_PHP視頻教程

    江湖傳言:PHP是世界上最好的編程語言。真的是這樣嗎?這個梗究竟是從哪來的?學會本課程,你就會明白了。 PHP中文網出品的PHP入門系統教學視頻,完全從初學者的角度出發,絕不玩虛的,一切以實用、有用...

    獨孤九賤(1)_HTML5視頻教程

    獨孤九賤(1)_HTML5視頻教程

    《php.cn原創html5視頻教程》課程特色:php中文網原創幽默段子系列課程,以惡搞,段子為主題風格的php視頻教程!輕松的教學風格,簡短的教學模式,讓同學們在不知不覺中,學會了HTML知識。 ...

    ThinkPHP5實戰之[教學管理系統]

    ThinkPHP5實戰之[教學管理系統]

    本套教程,以一個真實的學校教學管理系統為案例,手把手教會您如何在一張白紙上,從零開始,一步一步的用ThinkPHP5框架快速開發出一個商業項目。

    PHP入門視頻教程之一周學會PHP

    PHP入門視頻教程之一周學會PHP

    所有計算機語言的學習都要從基礎開始,《PHP入門視頻教程之一周學會PHP》不僅是PHP的基礎部分更主要的是PHP語言的核心技術,是學習PHP必須掌握的內容,任何PHP項目的實現都離不開這部分的內容,通...

    相關視頻教程

  • python教程之Django視頻教程 python教程之Django視頻教程
  • Python教程之Tkinter視頻教程 Python教程之Tkinter視頻教程
  • Python教程之開發跨平臺的記事本視頻教程 Python教程之開發跨平臺的記事本視頻教程
  • Python Web入門視頻教程 Python Web入門視頻教程
  • 零基礎入門Python項目實戰 零基礎入門Python項目實戰
  • 相關視頻章節

    第六期線上培訓班 中国体彩网唯一官网