依存语法

Published: 10 May 2016 Category: Notes

依存语法


依存语法

与短语结构语法比较起来,依存语法没有词组这个层次,每一个结点都与句子中的单词相对应,它能直接处理句子中词与词之间的关系,而结点数目大大减少了,便于直接标注词性,具有简明清晰的长处。特别在语料库文本的自动标注中,使用起来比短语结构语法方便。

一般而言,短语结构语法是与依存语法等价的。因此,如果我们在短语结构分析之后得到了短语结构树,可以自动地把这样的短语结构树转换为依存树。

如果在短语结构树中,确定了结点之间的依存关系,把处于支配地位的词叫做主词,处于依存地位的词叫做从词,那么,就可以把短语结构树转化为依存树,转换的步骤是:

  • 从叶子结点开始,首先把表示具体单词的结点归结到表示词类的结点上;
  • 然后,自底向上把主词归结到父结点上;
  • 最后再把全句的中心主词归结到根结点上。

通过这样的步骤,便可以得到与短语结构树等价的依存树。
由此可见,依存语法与短语结构语法具有等价性。通过有穷的步骤,我们不难实现短语结构语法和依存语法之间的相互转化。

在20世纪70年代,Robinson提出依存语法中关于依存关系的四条公理,在处理中文信息的研究中,中国学者提出了依存关系的第五条公理,如下:

  • 一个句子中只有一个成分是独立的;
  • 其它成分直接依存于某一成分;
  • 任何一个成分都不能依存与两个或两个以上的成分;
  • 如果A成分直接依存于B成分,而C成分在句中位于A和B之间,那么C或者直接依存于B,或者直接依存于A和B之间的某一成分;
  • 中心成分左右两面的其它成分相互不发生关系。

句子成分间相互支配与被支配、依存与被依存的现象普遍存在于汉语的词汇(合成语)、短语、单句、复合直到句群的各级能够独立运用的语言单位之中,这一特点为依存关系的普遍性,依存句法分析可以反映出句子各成分之间的语义修饰关系,它可以获得长距离的搭配信息,并与句子成分的物理位置无关。

句法分析工具总结:

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;

public class DepParser {
    private static JointParser parser;

    public static void main(String[] args) throws Exception {
        parser = new JointParser("../models/dep.m");

        System.out.println("得到支持的依存关系类型集合");
        System.out.println(parser.getSupportedTypes());

        String word = "中国进出口银行与中国银行加强合作。";
        test(word);

    }

    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();
        }
    }
}
#include <iostream>
#include <vector>

#include "ltp/parser_dll.h"

int main(int argc, char * argv[]) {
  if (argc < 2) {
    return -1;
  }

  void * engine = parser_create_parser(argv[1]);
  if (!engine) {
    return -1;
  }

  std::vector<std::string> words;
  std::vector<std::string> postags;

  words.push_back("一把手");  postags.push_back("n");
  words.push_back("亲自");    postags.push_back("d");
  words.push_back("过问");    postags.push_back("v");
  words.push_back("。");      postags.push_back("wp");

  std::vector<int>      heads;
  std::vector<std::string>  deprels;

  parser_parse(engine, words, postags, heads, deprels);

  for (int i = 0; i < heads.size(); ++ i) {
    std::cout << words[i] << "\t" << postags[i] << "\t"
              << heads[i] << "\t" << deprels[i] << std::endl;
  }

  parser_release_parser(engine);
  return 0;
}
package com.hankcs.demo;

import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.corpus.dependency.CoNll.CoNLLSentence;
import com.hankcs.hanlp.corpus.dependency.CoNll.CoNLLWord;

public class DemoDependencyParser
{
    public static void main(String[] args)
    {
        CoNLLSentence sentence = HanLP.parseDependency("徐先生还具体帮助他确定了把画雄鹰、松鼠和麻雀作为主攻目标。");
        System.out.println(sentence);
        // 可以方便地遍历它
        for (CoNLLWord word : sentence)
        {
            System.out.printf("%s --(%s)--> %s\n", word.LEMMA, word.DEPREL, word.HEAD.LEMMA);
        }
        // 也可以直接拿到数组,任意顺序或逆序遍历
        CoNLLWord[] wordArray = sentence.getWordArray();
        for (int i = wordArray.length - 1; i >= 0; i--)
        {
            CoNLLWord word = wordArray[i];
            System.out.printf("%s --(%s)--> %s\n", word.LEMMA, word.DEPREL, word.HEAD.LEMMA);
        }
        // 还可以直接遍历子树,从某棵子树的某个节点一路遍历到虚根
        CoNLLWord head = wordArray[12];
        while ((head = head.HEAD) != null)
        {
            if (head == CoNLLWord.ROOT) System.out.println(head.LEMMA);
            else System.out.printf("%s --(%s)--> ", head.LEMMA, head.DEPREL);
        }
    }
}
package edu.stanford.nlp.parser.nndep.demo; 
import edu.stanford.nlp.util.logging.Redwood;

import edu.stanford.nlp.ling.HasWord;
import edu.stanford.nlp.ling.TaggedWord;
import edu.stanford.nlp.parser.nndep.DependencyParser;
import edu.stanford.nlp.process.DocumentPreprocessor;
import edu.stanford.nlp.tagger.maxent.MaxentTagger;
import edu.stanford.nlp.trees.GrammaticalStructure;

import java.io.StringReader;
import java.util.List;

public class DependencyParserDemo  {

  /** A logger for this class */
  private static Redwood.RedwoodChannels log = Redwood.channels(DependencyParserDemo.class);
  public static void main(String[] args) {
    String modelPath = DependencyParser.DEFAULT_MODEL;
    String taggerPath = "edu/stanford/nlp/models/pos-tagger/english-left3words/english-left3words-distsim.tagger";

    for (int argIndex = 0; argIndex < args.length; ) {
      switch (args[argIndex]) {
        case "-tagger":
          taggerPath = args[argIndex + 1];
          argIndex += 2;
          break;
        case "-model":
          modelPath = args[argIndex + 1];
          argIndex += 2;
          break;
        default:
          throw new RuntimeException("Unknown argument " + args[argIndex]);
      }
    }

    String text = "I can almost always tell when movies use fake dinosaurs.";

    MaxentTagger tagger = new MaxentTagger(taggerPath);
    DependencyParser parser = DependencyParser.loadFromModelFile(modelPath);

    DocumentPreprocessor tokenizer = new DocumentPreprocessor(new StringReader(text));
    for (List<HasWord> sentence : tokenizer) {
      List<TaggedWord> tagged = tagger.tagSentence(sentence);
      GrammaticalStructure gs = parser.predict(tagged);

      // Print typed dependencies
      log.info(gs);
    }
  }
}

语义角色标注

语义角色标注技术按照现代语法知识将词语序列分组,并按照语义角色对它们进行分类,它体现句子基本意思,该方法不对整个句子做详细的语义分析,只是标注句子中给定谓词(动词、名词等)的语义角色(参数),从而是计算机对语句有一个“浅层”的理解,就是对于给定句子中的每个谓词(动词、名词等)分析出其中的相应语义成分,并作相应的语义标记,如施事、受事、工具或附加语等。语义角色标注是浅层语义分析的一种实现方式,它不对整个句子进行详细的语义分析,实质是在句子级别进行浅层的语义分析,具有分析任务定义明确,便于评价等优点。

目前研究比较热门的技术有:基于依存关系的语义角色标注、基于特征向量的语义角色标注等。

  • 基于依存句法关系的语义角色标注
    通过依存关系,依存树可以直接对与谓词节点相连的语义角色结构进行编码。
  • 基于特征向量的语义角色标注
    比较文本信息中不同特点和特征,以基本的特征和语料数据资源为基础,筛选便于识别和分类的特征进行语义角色标注。
  • 基于最大熵分类器的语义角色标注 预测了全部能够在句法分析树中找到匹配成分的角色后,采用简单的后处理规则去识别那些找不到匹配成分的角色。
  • 基于特征向量的语义角色标注
    可以通过计算核函数隐式达到降维,降低时间和空间复杂性,实现语义角色标注技术。
  • 基于条件随机场的语义角色标注 它以浅层句法分析为基础,把短语或命名实体作为标注的基本单元,将条件随机场模型用于句子中谓词的语义角色标注。

相关连接

comments powered by Disqus