调研了一下依存句法分析,了解了依存句法分析是什么,有什么用,并试用了两个NLP库的句法分析。
依存关系分析是什么
句法分析(syntactic parsing)是自然语言处理中的关键技术之一, 其基本任务是确定句子的句法结构或句子中词汇之间的依存关系。并将句子的语法结构表示为容易理解的结构(通常是树形结构)。
依存句法认为“谓语”中的动词是一个句子的中心,其他成分与动词直接或间接地产生联系。
“依存”指词与词之间支配与被支配的关系,这种关系不是对等的。这种从属关系是由支配词和从属词联结而成。
依存句法本身没有规定要对依存关系进行分类,但为了丰富依存结构传达的句法信息,在实际应用中,一般会给依存树的边加上不同的标记。
依存句法分析的作用
假如要翻译以下两个句子。
对于句式灵活的句子,如果不考虑其语法结构,很难直接给用户返回正确的结果。
为了让计算机能够分清指代关系,句法分析非常重要,更是下一步语义分析的前提。
比如“去医院看癌症病人”,“看”可以有“治疗”的意思也有“看望”的意思,容易产生歧义。如果引入句法分析,就会确定意思为“看望”,因为“看”的宾语是“病人”。
API
调研了两个NLP库,分别对句子“1998年11月11日,马化腾和同学张志东在广东省深圳市正式注册成立‘深圳市腾讯计算机系统有限公司’。”进行词法分析,对比效果。
HanLP
https://github.com/hankcs/pyhanlp
from pyhanlp import *
if __name__=="__main__":
sentence=HanLP.parseDependency("1998年11月11日,马化腾和同学张志东在广东省深圳市正式注册成"
"立‘深圳市腾讯计算机系统有限公司’。")
print(sentence)
#print(dir(sentence)) #dir()可以查看sentence的方法、属性
'''
for word in sentence.iterator():
print("%s --(%s)--> %s" % (word.LEMMA, word.DEPREL, word.HEAD.LEMMA))
print()
'''
# 也可以直接拿到数组,任意顺序或逆序遍历
word_array=sentence.getWordArray()
for word in word_array:
print("%s --(%s)--> %s" % (word.LEMMA, word.DEPREL, word.HEAD.LEMMA))
print()
# 还可以直接遍历子树,从某棵子树的某个节点一路遍历到虚根
CoNLLWord = JClass("com.hankcs.hanlp.corpus.dependency.CoNll.CoNLLWord")
head = word_array[12]
while head.HEAD:
head = head.HEAD
if (head == CoNLLWord.ROOT):
print(head.LEMMA)
else:
print(" % s - -(% s) --> " % (head.LEMMA, head.DEPREL))
输出结果
1 1998年 1998年 nt t _ 2 定中关系 _ _
2 11月11日 11月11日 nt t _ 11 状中结构 _ _
3 , , wp w _ 2 标点符号 _ _
4 马化腾 马化腾 nh nr _ 7 定中关系 _ _
5 和 和 c c _ 6 左附加关系 _ _
6 同学 同学 n n _ 4 并列关系 _ _
7 张志东 张志东 nh nr _ 11 主谓关系 _ _
8 在 在 p p _ 11 状中结构 _ _
9 广东省深圳市 广东省深圳市 ns ns _ 8 介宾关系 _ _
10 正式 正式 a ad _ 11 状中结构 _ _
11 注册 注册 v v _ 0 核心关系 _ _
12 成立 成立 v v _ 11 并列关系 _ _
13 ‘ ‘ wp w _ 14 标点符号 _ _
14 深圳市腾讯计算机系统有限公司 深圳市腾讯计算机系统有限公司 ni nt _ 12 动宾关系 _ _
15 ’ ’ wp w _ 14 标点符号 _ _
16 。 。 wp w _ 11 标点符号 _ _
1998年 --(定中关系)--> 11月11日
11月11日 --(状中结构)--> 注册
, --(标点符号)--> 11月11日
马化腾 --(定中关系)--> 张志东
和 --(左附加关系)--> 同学
同学 --(并列关系)--> 马化腾
张志东 --(主谓关系)--> 注册
在 --(状中结构)--> 注册
广东省深圳市 --(介宾关系)--> 在
正式 --(状中结构)--> 注册
注册 --(核心关系)--> ##核心##
成立 --(并列关系)--> 注册
‘ --(标点符号)--> 深圳市腾讯计算机系统有限公司
深圳市腾讯计算机系统有限公司 --(动宾关系)--> 成立
’ --(标点符号)--> 深圳市腾讯计算机系统有限公司
。 --(标点符号)--> 注册
深圳市腾讯计算机系统有限公司 - -(动宾关系) -->
成立 - -(并列关系) -->
注册 - -(核心关系) -->
##核心##
FudanNLP
https://github.com/FudanNLP/fnlp
用提供的demo来进行使用
package org.fnlp.demo.nlp;
import org.fnlp.nlp.cn.tag.POSTagger;
import org.fnlp.nlp.parser.dep.DependencyTree;
import org.fnlp.nlp.parser.dep.JointParser;
/**
* 依存句法分析使用示例
* @author xpqiu
*
*/
public class DepParser {
private static JointParser parser;
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
parser = new JointParser("./models/dep.m");
System.out.println("得到支持的依存关系类型集合");
System.out.println(parser.getSupportedTypes());
String word = "1998年11月11日,马化腾和同学张志东在广东省深圳市正式注册成立‘深圳市腾讯计算机系统有限公司’。";
test(word);
}
/**
* 只输入句子,不带词性
* @throws Exception
*/
private static void test(String word) throws Exception {
POSTagger tag = new POSTagger("./models/seg.m","./models/pos.m");
String[][] s = tag.tag2Array(word);
try {
DependencyTree tree = parser.parse2T(s[0],s[1]);
System.out.println(tree.toString());
String stree = parser.parse2String(s[0],s[1],true);
System.out.println(stree);
} catch (Exception e) {
e.printStackTrace();
}
}
}
得到输出结果
0 1998年 时间短语 2 定语
1 11月 时间短语 2 定语
2 11日 时间短语 7 定语
3 , 标点 2 标点
4 马化腾 人名 7 并列
5 和 并列连词 4 关联
6 同学 名词 7 定语
7 张志东 人名 -1 核心词
8 在 介词 7 标点
9 广东省 地名 10 定语
10 深圳市 地名 8 介宾
11 正式 副词 12 状语
12 注册 动词 8 介宾
13 成立 动词 12 并列
14 ‘ 标点 20 标点
15 深圳市 地名 20 定语
16 腾讯 机构名 20 定语
17 计算机 名词 18 定语
18 系统 名词 20 定语
19 有限 形容词 20 定语
20 公司 名词 13 宾语
21 ’ 标点 20 标点
22 。 标点 8 标点
1998年 11月 11日 , 马化腾 和 同学 张志东 在 广东省 深圳市 正式 注册 成立 ‘ 深圳市 腾讯 计算机 系统 有限 公司 ’ 。
时间短语 时间短语 时间短语 标点 人名 并列连词 名词 人名 介词 地名 地名 副词 动词 动词 标点 地名 机构名 名词 名词 形容词 名词 标点 标点
2 2 7 2 7 4 7 -1 7 10 8 12 8 12 20 20 20 18 20 20 13 20 8
定语 定语 定语 标点 并列 关联 定语 核心词 标点 定语 介宾 状语 介宾 并列 标点 定语 定语 定语 定语 定语 宾语 标点 标点
对比
效果对比
对于句子 “上海浦东机场西货运区货运工王某某被确诊为新冠肺炎”。
HanLP结果
1 上海浦东机场 上海浦东机场 ni nt _ 4 定中关系 _ _
2 西 西 nd f _ 3 定中关系 _ _
3 货运区 货运区 n n _ 4 定中关系 _ _
4 货运工 货运工 n n _ 5 定中关系 _ _
5 王某某 王某某 nh nr _ 7 前置宾语 _ _
6 被 被 p p _ 7 状中结构 _ _
7 确诊 确诊 v v _ 0 核心关系 _ _
8 为 为 v v _ 7 动补结构 _ _
9 新冠肺炎 新冠肺炎 n n _ 8 动宾关系 _ _
10 。 。 wp w _ 7 标点符号 _ _
fudanNLP结果
0 上海 地名 1 定语
1 浦东 地名 4 定语
2 机场 名词 4 定语
3 西货运区 名词 4 定语
4 货运工 名词 5 定语
5 王某某 人名 6 主语
6 被 被动词 -1 核心词
7 确诊 动词 6 补语
8 为 介词 7 补语
9 新 形容词 10 定语
10 冠肺炎 名词 8 介宾
11 。 标点 6 标点
fudanNLP对于“新冠肺炎”这个分词并不准确,同时核心词感觉也不准确。
时间效率对比
HanLP
可以看出HanLP的python版本和Java版本的运行速度是差不多的。
FudanNLP
fudanNLP的速度要稍快于HanLP
参考链接
句法分析 (syntactic parsing) 在 NLP 领域的应用是怎样的? - cstghitpku的回答 - 知乎
https://www.zhihu.com/question/39034550/answer/79419855
https://blog.csdn.net/zkq_1986/article/details/106412110
https://www.cnblogs.com/smartisn/p/13823316.html