NLP(十二)依存句法分析的視覺化及圖分析

jclian91發表於2019-07-29

  依存句法分析的效果雖然沒有像分詞、NER的效果來的好,但也有其使用價值,在日常的工作中,我們免不了要和其打交道。筆者這幾天一直在想如何分析依存句法分析的結果,一個重要的方面便是其視覺化和它的圖分析。
  我們使用的NLP工具為jieba和LTP,其中jieba用於分詞,LTP用於詞性標註和句法分析,需要事件下載pos.modelparser.model檔案。
  本文使用的示例句子為:

2018年7月26日,華為創始人任正非向5G極化碼(Polar碼)之父埃爾達爾教授舉行頒獎儀式,表彰其對於通訊領域做出的貢獻。

  首先,讓我們來看一下沒有視覺化效果之前的句法分析結果。Python程式碼如下:

# -*- coding: utf-8 -*-

import os
import jieba
from pyltp import  Postagger, Parser

sent = '2018年7月26日,華為創始人任正非向5G極化碼(Polar碼)之父埃爾達爾教授舉行頒獎儀式,表彰其對於通訊領域做出的貢獻。'

jieba.add_word('Polar碼')
jieba.add_word('5G極化碼')
jieba.add_word('埃爾達爾')
jieba.add_word('之父')
words = list(jieba.cut(sent))

print(words)

# 詞性標註
pos_model_path = os.path.join(os.path.dirname(__file__), 'data/pos.model')
postagger = Postagger()
postagger.load(pos_model_path)
postags = postagger.postag(words)

# 依存句法分析
par_model_path = os.path.join(os.path.dirname(__file__), 'data/parser.model')
parser = Parser()
parser.load(par_model_path)
arcs = parser.parse(words, postags)

rely_id = [arc.head for arc in arcs]  # 提取依存父節點id
relation = [arc.relation for arc in arcs]  # 提取依存關係
heads = ['Root' if id == 0 else words[id-1] for id in rely_id]  # 匹配依存父節點詞語

for i in range(len(words)):
    print(relation[i] + '(' + words[i] + ', ' + heads[i] + ')')

輸出結果如下:

['2018', '年', '7', '月', '26', '日', ',', '華為', '創始人', '任正非', '向', '5G極化碼', '(', 'Polar碼', ')', '之父', '埃爾達爾', '教授', '舉行', '頒獎儀式', ',', '表彰', '其', '對於', '通訊', '領域', '做出', '的', '貢獻', '。']
ATT(2018, 年)
ATT(年, 日)
ATT(7, 月)
ATT(月, 日)
ATT(26, 日)
ADV(日, 舉行)
WP(,, 日)
ATT(華為, 創始人)
ATT(創始人, 任正非)
SBV(任正非, 舉行)
ADV(向, 舉行)
ATT(5G極化碼, 之父)
WP((, Polar碼)
COO(Polar碼, 5G極化碼)
WP(), Polar碼)
ATT(之父, 埃爾達爾)
ATT(埃爾達爾, 教授)
POB(教授, 向)
HED(舉行, Root)
VOB(頒獎儀式, 舉行)
WP(,, 舉行)
COO(表彰, 舉行)
ATT(其, 貢獻)
ADV(對於, 做出)
ATT(通訊, 領域)
POB(領域, 對於)
ATT(做出, 貢獻)
RAD(的, 做出)
VOB(貢獻, 表彰)
WP(。, 舉行)

我們得到了該句子的依存句法分析的結果,但是其視覺化效果卻不好。
  我們使用Graphviz工具來得到上述依存句法分析的視覺化結果,程式碼(接上述程式碼)如下:

from graphviz import Digraph

g = Digraph('測試圖片')

g.node(name='Root')
for word in words:
    g.node(name=word)

for i in range(len(words)):
    if relation[i] not in ['HED']:
        g.edge(words[i], heads[i], label=relation[i])
    else:
        if heads[i] == 'Root':
            g.edge(words[i], 'Root', label=relation[i])
        else:
            g.edge(heads[i], 'Root', label=relation[i])

g.view()

得到的依存句法分析的視覺化圖片如下:

NLP(十二)依存句法分析的視覺化及圖分析

在這張圖片中,我們有了對依存句法分析結果的直觀感覺,效果也非常好,但是遺憾的是,我們並不能對上述視覺化結果形成的圖(Graph)進行圖分析,因為Graphviz僅僅只是一個視覺化工具。那麼,我們該用什麼樣的工具來進行圖分析呢?
  答案就是NetworkX。以下是筆者對於NetworkX應用於依存句法分析的視覺化和圖分析的展示,其中圖分析展示了兩個節點之間的最短路徑。示例的Python程式碼如下:

# 利用networkx繪製句法分析結果
import networkx as nx
import matplotlib.pyplot as plt
from pylab import mpl

mpl.rcParams['font.sans-serif'] = ['Arial Unicode MS']  # 指定預設字型


G = nx.Graph()  # 建立無向圖G

# 新增節點
for word in words:
    G.add_node(word)

G.add_node('Root')

# 新增邊
for i in range(len(words)):
    G.add_edge(words[i], heads[i])

source = '5G極化碼'
target1 = '任正非'
distance1 = nx.shortest_path_length(G, source=source, target=target1)
print("'%s'與'%s'在依存句法分析圖中的最短距離為:  %s" % (source, target1, distance1))

target2 = '埃爾達爾'
distance2 = nx.shortest_path_length(G, source=source, target=target2)
print("'%s'與'%s'在依存句法分析圖中的最短距離為:  %s" % (source, target2, distance2))

nx.draw(G, with_labels=True)
plt.savefig("undirected_graph.png")

得到的視覺化圖片如下:

NLP(十二)依存句法分析的視覺化及圖分析

輸出的結果如下:

'5G極化碼'與'任正非'在依存句法分析圖中的最短距離為:  6
'5G極化碼'與'埃爾達爾'在依存句法分析圖中的最短距離為:  2

  本次到此結束,希望這篇簡短的文章能夠給讀者帶來一些啟發~

注意:不妨瞭解下筆者的微信公眾號: Python爬蟲與演算法(微訊號為:easy_web_scrape), 歡迎大家關注~

相關文章