文本可視化(二)——《今生今世》人物關系可視化python實現
作者:Sinte-Beuve
接上篇: 文本可視化(一)——《今生今世》詞云生成與小說分析
在文本可視化[一]——《今生今世》詞云生成與小說分析一文中,我使用了jieba分詞和wordcloud實現了,文本關鍵詞的提取并生成詞云,同時也嘗試直接提取人名關鍵詞來繪制。這次我們換一種方式——通過分析人物之間的關系,而不是人物在文本集中的頻率來繪制一張復雜網絡圖,如下所示。數據經過可視化后還是非常有趣的。下面就講講人物關系網圖的實過程。
用到的工具
-
jieba
jieba分詞,最好用的開源中文分詞工具。他最主要的兩個功能是分詞和關鍵詞的抽取。在 文本可視化[一]——《今生今世》詞云生成與小說分析 ?使用了關鍵詞抽取,在這里我們需要用他的分詞功能來提取文本中的人名。 -
gephi
gephi是一個開源的復雜網絡數據可視化軟件,可用于探索數據分析、鏈路分析、社交網絡分析、生物網絡分析等。我們需要把數據處理成gephi可接受的csv格式,然后再進行繪制。
數據處理方式
在詞云中,我們只能通過詞的大小來了解該詞對于文本集是否起關鍵作用,無法探究人物之間的關系;在關系網圖中,不僅可以了解詞的關鍵程度,還能發現人物之間的聯系,更能說明問題。
由此可見,繪制詞云時,我們只需要提取兩列數據,一列人名,一列為頻率。而繪制網絡圖時,就需要兩組數據。網絡圖,顧名思義,就是一張圖。所有的圖都是由節點和邊構成的。節點數據也就是節點值+權重,邊數據就是出度+入度+權重。
對應到本文的例子中來,我們是來繪制《今生今世》中的任務關系網。具體的處理方式如下:
- 對文本進行針對性分詞,統計人物在本文中的出場次數。
- 以段落為單位進行劃分,統計每段中的人物,兩兩配對后計數,形成粗略的人物關系統計。
- 數據為gephi特定的csv格式,人物出場次數輸出為格式為(Id,Label,Weight),人物關系輸出格式為(Source,Target,Weigh)。這也就是之前所說的,用來繪制圖的節點和邊數據。
可能存在的問題
根據上文描述的統計方法來進行統計顯然是粗略的,有很多問題需要進一步考量。
- 以自然段為單位統計人物關系是否合理?真實情況中有很多跨段落的人物關系。
- 顯然利用笛卡爾積來統計人物之間的關系也是有問題的。
- 人物之前的稱呼僅僅是直呼姓名的嗎?顯然還有多種代詞,這里我將文本中的“我”也一并提取出來作為《今生今世》的中心人物——胡蘭成。
結果雖然是粗略的,但是通過對文本的理解,繪制的圖依然有一定的參考意義。
實現流程
代碼實現分為三步,1. 人物出場次數統計。2. 人物關系統計。3. 格式化輸出。
準備工作
準備兩份字典,用于分詞。
-
文本人物字典
文本人物字典包含了文本中的大部分人名,或者說是我們關心的人物的人名。
-
人物別稱映射字典
民國時期的散文,勢必每個人會有多個稱呼,在文化人中甚多。蕊生、我、蘭成、胡先生指代的都是胡蘭成。因此需要一個映射字典,將不同的稱呼都映射到同一個人名當中。
定義文件路徑常量和初始化全局變量
TEXT_PATH = '../jsjs.txt' # 文本路徑 DICT_PATH = 'person.txt' # 人物字典路徑 SYNONYMOUS_DICT_PATH = 'synonymous_dict.txt' # 同義詞路徑 SAVE_NODE_PATH = 'node.csv' SAVE_EDGE_PATH = 'edge.csv' ''' person_counter是一個計數器,用來統計人物出現的次數。{'a':1,'b':2} person_per_paragraph每段文字中出現的人物[['a','b'],[]] relationships保存的是人物間的關系。key為人物A,value為字典,包含人物B和權值。 ''' person_counter = defaultdict(int) # 人物出場次數計數器 person_per_paragraph = [] relationships = {} synonymous_dict = {}
人物出場次數統計
具體實現方式可以看代碼注釋。
def count_person(self): ''' 統計人物出場次數,添加每段的人物 :return: ''' paragraphs = self.get_clean_paragraphs() synonymous = self.synonymous_names() print('start process node') with codecs.open(self._dict_path, 'r', 'utf-8') as f: name_list = f.read().split(' 10 nr\r\n') # 獲取干凈的name_list for p in paragraphs: jieba.load_userdict(self._dict_path) # 分詞,為每一段初始化新字典 poss = jieba.cut(p) self._person_per_paragraph.append([]) for w in poss: # 判斷是否在姓名字典以及同義詞區分 if w not in name_list: continue if synonymous.get(w): w = synonymous[w] # 往每段中添加人物 self._person_per_paragraph[-1].append(w) # 初始化人物關系,計數 if self._person_counter.get(w) is None: self._relationships[w] = {} self._person_counter[w] += 1 return self._person_counter
人物關系統計
def calc_relationship(self): ''' 統計人物關系權值 :return: ''' print("start to process edge") # 遍歷每一段落,笛卡爾積形式,統計人物關系 for p in self._person_per_paragraph: for name1 in p: for name2 in p: if name1 == name2: continue if self._relationships[name1].get(name2) is None: self._relationships[name1][name2] = 1 else: self._relationships[name1][name2] += 1 return self._relationships
格式化輸出
def save_node_and_edge(self): ''' 根據dephi格式保存為csv :return: ''' with codecs.open(SAVE_NODE_PATH, "a+", "utf-8") as f: f.write("Id,Label,Weight\r\n") for name, times in self._person_counter.items(): f.write(name + "," + name + "," + str(times) + "\r\n") with codecs.open(SAVE_EDGE_PATH, "a+", "utf-8") as f: f.write("Source,Target,Weight\r\n") for name, edges in self._relationships.items(): for v, w in edges.items(): if w > 3: f.write(name + "," + v + "," + str(w) + "\r\n") print('save file successful!')
輸出結果如下圖所示。
完整代碼參考github
接下來就可以把數據導入到gephi中生成人物關系網圖了。
gephi的使用
gephi和之前使用的wordcloud不同,wordcloud僅僅是一個python的庫,直接通過函數調用就可以繪制圖片。gephi是一個可視化的應用程序。
需要在https://gephi.org/ 下載windows版的安裝包進行安裝。打開后如下圖所示。
接下來就可以進行網圖的繪制了。
1. 新建工程,導入數據
- 新建工程
- 選擇數據資料tab,點擊輸入數字表格,添加節點和邊的csv數據。
2.調整相關的樣式
點擊概覽調整相關樣式。可以通過度,權重等信息修改相關的樣式。
3. 修改字體,顯示相應的標簽
4. 選擇一個自動化布局的方式,預覽,再調整相關參數
5. 最終點擊左下角導出圖片
上面簡單描述了下生成網圖的過程。gephi具體的使用方式可以去查看官網的教程。
End.
轉載請注明來自36大數據(36dsj.com): 36大數據 ? 文本可視化(二)——《今生今世》人物關系可視化python實現