乐趣区

NLP十二依存句法分析的可视化及图分析

  依存句法分析的效果虽然没有像分词、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()

得到的依存句法分析的可视化图片如下:

在这张图片中,我们有了对依存句法分析结果的直观感觉,效果也非常好,但是遗憾的是,我们并不能对上述可视化结果形成的图(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")

得到的可视化图片如下:

输出的结果如下:

'5G 极化码' 与 '任正非' 在依存句法分析图中的最短距离为:  6
'5G 极化码' 与 '埃尔达尔' 在依存句法分析图中的最短距离为:  2

  本次到此结束,希望这篇简短的文章能够给读者带来一些启发~

注意:不妨了解下笔者的微信公众号:Python 爬虫与算法(微信号为:easy_web_scrape),欢迎大家关注~

退出移动版