一 概念:
从属词:一个词修饰另一个词
支配词:被修饰的词语
依存关系:从属词与支配词间语法关系
依存句法树:将一个句子中所有词语的依存关系以有 向的形式表示出来,就会得到一颗树
依存句法树库:由大量人工标注的依存句法树组成的语料库
依存句法分析:分析句子的依存语法的一种中高级NLP人物,其输入通常是词语与词性,输出则是一棵依存句法树。
二 基于转移的依存句法分析流程:
将一棵依存句法树的构建过程表示为两个动作,如果机器学习模型能够根据句子的某些特征准确预测这些动作,那么计算机能够根据这些动作拼装出正确的依存句法树了。这种拼装动作称为转移
a.确定转移系统
转移系统(虚拟机器)根据自己的状态和输入的单词预测下一步要执行的移动动作,最后根据转移动作拼装句法树
转移系统主要负责制定所有可执行的动作以及相应的条件
b.特征提取
有了特征之后,转移系统的一个状态就被表示为一个稀疏的二进制向量
c.规范:
将语料库中的依存句法树转换为正确的转移动作序列,以供机器 学习
c.分类器预测转移动作
三 代码:
训练模型
# -*- coding:utf-8 -*- # Author: hankcs # Date: 2019-02-11 23:18 # 《自然语言处理入门》12.5.1 训练模型 # 配套书籍:http://nlp.hankcs.com/book.php # 讨论答疑:https://bbs.hankcs.com/ from pyhanlp import * import zipfile import os from pyhanlp.static import download, remove_file, HANLP_DATA_PATH def test_data_path(): """ 获取测试数据路径,位于$root/data/test,根目录由配置文件指定。 :return: """ data_path = os.path.join(HANLP_DATA_PATH, 'test') if not os.path.isdir(data_path): os.mkdir(data_path) return data_path def ensure_data(data_name, data_url): root_path = test_data_path() dest_path = os.path.join(root_path, data_name) if os.path.exists(dest_path): return dest_path if data_url.endswith('.zip'): dest_path += '.zip' download(data_url, dest_path) if data_url.endswith('.zip'): with zipfile.ZipFile(dest_path, "r") as archive: archive.extractall(root_path) remove_file(dest_path) dest_path = dest_path[:-len('.zip')] return dest_path KBeamArcEagerDependencyParser = JClass('com.hankcs.hanlp.dependency.perceptron.parser.KBeamArcEagerDependencyParser') CTB_ROOT = ensure_data("ctb8.0-dep", "http://file.hankcs.com/corpus/ctb8.0-dep.zip") CTB_TRAIN = CTB_ROOT + "/train.conll"#训练集 CTB_DEV = CTB_ROOT + "/dev.conll" # 开发集 CTB_TEST = CTB_ROOT + "/test.conll" # 词聚类问件 CTB_MODEL = CTB_ROOT + "/ctb.bin" # 模型 BROWN_CLUSTER = ensure_data("wiki-cn-cluster.txt", "http://file.hankcs.com/corpus/wiki-cn-cluster.zip") if __name__ == '__main__': parser = KBeamArcEagerDependencyParser.train(CTB_TRAIN, CTB_DEV, BROWN_CLUSTER, CTB_MODEL) print(parser.parse("人吃鱼")) score = parser.evaluate(CTB_TEST) print("UAS=%.1f LAS=%.1f\n" % (score[0], score[1]))
意见抽取例子
# -*- coding:utf-8 -*- # Author: hankcs # Date: 2019-06-02 18:03 # 《自然语言处理入门》12.6 案例:基于依存句法树的意见抽取 # 配套书籍:http://nlp.hankcs.com/book.php # 讨论答疑:https://bbs.hankcs.com/ from pyhanlp import * CoNLLSentence = JClass('com.hankcs.hanlp.corpus.dependency.CoNll.CoNLLSentence') CoNLLWord = JClass('com.hankcs.hanlp.corpus.dependency.CoNll.CoNLLWord') IDependencyParser = JClass('com.hankcs.hanlp.dependency.IDependencyParser') KBeamArcEagerDependencyParser = JClass('com.hankcs.hanlp.dependency.perceptron.parser.KBeamArcEagerDependencyParser') def main(): parser = KBeamArcEagerDependencyParser() tree = parser.parse("电池非常棒,机身不长,长的是待机,但是屏幕分辨率不高。") print(tree) print("第一版") extactOpinion1(tree) print("第二版") extactOpinion2(tree) print("第三版") extactOpinion3(tree) def extactOpinion1(tree): for word in tree.iterator(): if word.POSTAG == "NN" and word.DEPREL == "nsubj": print("%s = %s" % (word.LEMMA, word.HEAD.LEMMA)) def extactOpinion2(tree): for word in tree.iterator(): if word.POSTAG == "NN" and word.DEPREL == "nsubj": if tree.findChildren(word.HEAD, "neg").isEmpty(): print("%s = %s" % (word.LEMMA, word.HEAD.LEMMA)) else: print("%s = 不%s" % (word.LEMMA, word.HEAD.LEMMA)) def extactOpinion3(tree): for word in tree.iterator(): if word.POSTAG == "NN": if word.DEPREL == "nsubj": # ①属性 if tree.findChildren(word.HEAD, "neg").isEmpty(): print("%s = %s" % (word.LEMMA, word.HEAD.LEMMA)) else: print("%s = 不%s" % (word.LEMMA, word.HEAD.LEMMA)) elif word.DEPREL == "attr": top = tree.findChildren(word.HEAD, "top") # ②主题 if not top.isEmpty(): print("%s = %s" % (word.LEMMA, top.get(0).LEMMA)) if __name__ == '__main__': main()