六-结构化提取

按照之前理解的内容,对一句话做处理,最多是切成一个一个的词,再标注上词性,仅此而已,然而事实并非如此,一句话还可以做更多的文章,我们本节见分晓

什么?还能结构化?

任何语言的每一句话之所以称为“话”,是因为它有一定的句子结构,除了一个个独立的词之外,他们之间还存在着某种关系。如果任何一句话可以由任何词构成,可长可短,那么这是一个非结构化的信息,计算机是很难理解并做计算的,但是如果能够以某种方式把句子转化成结构化的形式,计算机就可以理解了。

实事上,人脑在理解一句话的时候也暗暗地在做着由非结构化到结构化的工作。

比如说:我下午要和小明在公司讨论一个技术问题。这是一片非结构化的词语拼成的一句话,但是这里面有很多隐含信息:

  1. 小明是一个实体
  2. 参与者有两个:我和小明
  3. 地点设定是:公司
  4. 要做的事情是:讨论
  5. 讨论的内容是:问题
  6. 这个问题是一个技术问题
  7. 公司是一个地点
  8. 讨论是一种行为
  9. 我和小明有某种关系
  10. 下午是一个时间

上面这些信息有一些是专门针对这个句子的,有一些是常理性的,对于针对句子的信息有利于理解这句话,对于常理性的信息可以积累下来用来以后理解其他句子。

那么怎么才能把非结构化的句子转成结构化的信息呢?要做的工作除了断句、分词、词性标注之外,还要做的一个关键事情就是分块。

分块

分块就是根据句子中的词和词性,按照某种规则组合在一起形成一个个分块,每个分块代表一个实体。常见的实体包括:组织、人员、地点、日期、时间等

以上面的例子为例,首先我们做名词短语分块(NP-chunking. ,比如:技术问题。名词短语分块通过词性标记和一些规则就可以识别出来,也可以通过机器学习的方法识别

除了名词短语分块还有很多其他分块:介词短语(PP,比如:以我……. 、动词短语(VP,比如:打人. 、句子(S,我是人.

分块如何标记和存储呢?

可以采用IOB标记,I(inside,内部)、O(outside,外部)、B(begin, 开始),一个块的开始标记为B,块内的标识符序列标注为I,所有其他标识符标注为O

也可以用树结构来存储分块,用树结构可以解决IOB无法标注的另一类分块,那就是多级分块。多级分块就是一句话可以有多重分块方法,比如:我以我的最高权利惩罚你。这里面“最高权利”、“我的最高权利”、“以我的最高权利”是不同类型分块形成一种多级分块,这是无法通过IOB标记的,但是用树结构可以。这也叫做级联分块。具体树结构举个例子:

1
2
3
4
5
6
7
(S
    (NP 小明) 
    (VP
        (V 追赶) 
        (NP
            (Det 一只) 
            (N 兔子)))) 

这是不是让你想到了语法树?

关系抽取

通过上面的分块可以很容易识别出实体,那么关系抽取实际就是找出实体和实体之间的关系,这是自然语言处理一个质的跨越,实体识别让机器认知了一种事物,关系识别让机器掌握了一个真相。

关系抽取的第一个方法就是找到(X, a, Y)这种三元组,其中X和Y都是实体,a是表达关系的字符串,这完全可以通过正则来识别,因为不同语言有这不同的语法规则,所以方法都是不同的,比如中文里的“爱”可以作为这里的a,但是“和”、“因为”等就不能作为这里的a

编程实现

下面介绍部分有关分块的代码,因为中文标注好分块的语料没有找到,所以只能沿用英文语料来说明,但是原理是一样的

conll2000语料中已经有标注好的分块信息,如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
>>> from nltk.corpus import conll2000
>>> print conll2000.chunked_sents('train.txt')[99]
(S
  (PP Over/IN)
  (NP a/DT cup/NN)
  (PP of/IN)
  (NP coffee/NN)
  ,/,
  (NP Mr./NNP Stone/NNP)
  (VP told/VBD)
  (NP his/PRP$ story/NN)
  ./.)

我们可以基于这些标注数据做训练,由于这种存储结构比较特殊,所以就不单独基于这种结构实现parser了,只说下跟前面讲的机器学习一样,只要基于这部分数据做训练,然后再用来标注新的语料就行了