基於共現發現人物關系的python實現
參考鏈接:
提取《釜山行》人物關系,
用Python的networkx繪制精美網絡圖
1.共現關系
在文獻計量學中,關鍵詞的共詞方法常用來確定該文獻集所代表學科中各主題之間的關系。而在這里,我們需要通過分析一篇小說或劇本,來分析劇中各個角色之間的人物關系。兩者有很相同的地方。
一般我們認為,在一篇文章中的同一段出現的兩個人物之間,一定具有某種關聯,因此我們的程序的大致流程也可以確定下來。我們可以先做分詞,將每一段中的人物角色抽取出來,然后以段落為單位,統計兩個角色同時出現的出現次數,並把結果存在一個二維矩陣之中。這個矩陣也可以作為關系圖的矩陣,矩陣中的元素(統計的出現次數)就是邊的權值。
舉個例子,比如,現有三個段落的分詞結果如下:a/b/c,b/a/f,a/d/c,那么就是ab共現2次,ac共現2次,以此類推。
同時,為了方便,我們把人物和人物關系也通過文件記錄,我們要分析的人物關系則來自於人名的名義(小說)
2.jieba分詞
jieba分詞的原理和語法可以參考這篇文章《中文分詞的基本原理以及jieba分詞的用法》
雖然有jieba分詞可以對文章進行分析,但是仍然不是很准。比如,人名名義中有一個角色叫“易學習”,“易”是副詞,“學習”是動詞,因此很難將這個人名分出來。不過好在結巴分詞提供了自定義字典,我們就可以根據之前的分詞結果,一點一點去修正自己的字典即可。當然,我建議在構建自定義字典的時候,最好先直接把人名的名義的角色表直接抄一份過來,詞性全部標記成nr(人名)。
這樣我們就可以通過先分詞,然后篩選詞性的方式,把名字篩選出來。篩選出之后,就記錄到每一段的一個list中,用於后面的矩陣構成。
這個過程我們是以段落為單位進行的,因此可以設置一個全局字典來記錄每一個角色的權重(即詞頻統計)。代碼如下:
# 將劇本進行分詞,並將表示人名的詞提出,將其他停用詞和標點省略
# 提出人名的同時,同name字典記錄下來,作為矩陣的行和列
def cut_word(text):
words=pseg.cut(text)
L_name=[]
for x in words :
if x.flag!='nr' or len(x.word) < 2:
continue
if not Names.get(x.word):
Names[x.word]=1
else:
Names[x.word]=Names[x.word]+1
L_name.append(x.word)
return L_name
# 建立詞頻字典和每段中的人物列表
def namedict_built():
global Names
with open('e:/PY/relationship_find/test.txt','r') as f:
for l in f.readlines():
n=cut_word(l)
if len(n)>=2: # 由於要計算關系,空list和單元素list沒有用
Lines.append(n)
Names=dict(sorted(Names.items(),key = lambda x:x[1],reverse = True)[:36])
# print(Line)
3.構建矩陣
雖然嘴上說着矩陣,但實際上在代碼里使用二維字典完成的,因為這樣訪問起來比較快。統計也很簡(bao)單(li),就是把我們在上面得出的每一段的人物list都遍歷一遍。。.
由於,分詞結果總是會有一些奇怪的詞,所以,我們在構建矩陣的時候,直接以上面代碼中的Names中的人物為基准,濾掉其他不在Names中的詞,不然會有其他東西亂入。代碼如下:
# 通過遍歷Lines來構建貢獻矩陣
def relation_built():
for key in Names:
relationships[key]={}
for line in Lines:
for name1 in line:
if not Names.get(name1):
continue
for name2 in line:
if name1==name2 or (not Names.get(name2)):
continue
if not relationships[name1].get(name2):
relationships[name1][name2]= 1
else:
relationships[name1][name2] = relationships[name1][name2]+ 1
# print(relationships)