1. 程式人生 > >Python自然語言處理 8 分析句子結構

Python自然語言處理 8 分析句子結構

 前面的章節重點關注:如何識別它們,分析它們的結構,給它們分配詞彙類別,以及獲得它們的含義。

目的是要回答下列問題:

(1)如何使用形式化語法來描述無限的句子集合的結構?

(2)如何使用句法樹來表示句子結構?

(3)解析器如何分析句子並自動構建語法樹?

一 一些語法困境

#語言資料和無限可能性

文法的目的是給出一個明確的語言描述。而我們思考文法的方式與我們認為什麼是一種語言緊密聯絡在一起。觀察到的言語和書面文字是否是一個大卻有限的集合呢?關於文法句子是否存在一些更抽象的東西,如有能力的說話者能理解的隱性知識?或者是兩者的某種組合?我們不會解決這個問題,而是將介紹主要的方法。

#普遍存在的歧義

重要的目的是自然語言understanding,當識別一個文字所包含的語言結構時,可以從中獲得多少文字的含義?一段程式在通讀了一個文字後,它能否足夠“理解”文字,並回答一些簡答的問題,如“發生了什麼事“或”誰對誰做了什麼“?還像以前一樣,我們將開發簡單的程式來處理已註釋的語料庫,並執行有用的任務。

二 文法的用途

#超越n-grams



3 上下文無關文法

#一種簡單的文法

在NLTK中,上下文無關文法定義在nltk.grammar模組

import nltk
from nltk import CFG
//grammar1 = CFG.fromstring("""
grammar1 = nltk.parse_cfg("""
s -> NP VP
VP -> V NP | V NP PP
PP -> P NP
V -> "saw" | "ate" | "walked"
NP -> "John" | "Mary" | "Bob" | Det N | Det N PP
Det -> "a" | "an" | "the" | "my"
N -> "man" | "dog" | "cat" | "telescope" | "park"
P -> "in" | "on" | "by" | "with"
""")
sent = "Mary saw Bob".split()
rd_parser = nltk.RecursiveDescentParser(grammar1)
for tree in rd_parser.nbest_parse(sent):
    print tree
如果使用上述文法分析句子The dog saw a man in the park,結果將得到兩棵樹,被稱為結構上有歧義

#編寫你自己的文法

編寫mygrammar.cfg

grammar1 = nltk.data.load('file:mygrammar.cfg')

#句法結構中的遞迴

產生式左側的文法型別也出現在右側,那麼這個文法被認為是遞迴的

四 上下文無關文法分析

解析器根據文法產生式處理輸入的句子,並建立一個或多個符合文法的組成結構。

例如問答系統對提交的問題首先進行文法分析

在本節中,我們將看到兩個簡單的分析演算法,一種自上而下的方法稱為下降遞迴分析,一種自下而上的方法稱為移進-歸約分析。

以及更復雜的演算法,一種稱為左角落分析的帶自下而上過濾的自上而下的方法:一種稱為圖表分析的動態規劃技術

#遞迴下降解析器

nltk.RecursiveDescentParser(grammar1)

#移進-歸約分析

nltk.ShiftReduceParser(grammar1)

#左角落解析器

帶自下而上過濾的自上而下的解析器

#符合語句規則的子串表

////////

五 依存關係和依存文法

短語結構文法是關於詞和詞序列如何結合形成句子成分的。

一種獨特且互補的方式,依存文法,集中關注的是詞與其他詞之間的關係。

依存關係是一箇中心詞與其從屬之間的二元非對稱關係。一個句子的中心詞通常是動詞,所有其他詞要麼依賴於中心詞,要麼通過依賴路徑與它相關聯。

與短語結構文法相比,依存文法可以作為一種依存關係用來直接表示語法功能。

#配價與詞彙


在表中的動詞被認為具有不同的配價。配價限制不僅適用於動詞,也適用於其他類的中心詞。

#擴大規模

文法是否可以擴大到能覆蓋自然語言中的大型語料庫

使用各種正規工具

六 文法開發

如何訪問樹庫,及開發覆蓋廣泛文法所具有的挑戰

#樹庫和文法

corpus模組定義了樹庫語料的閱讀器,其中包含了賓州樹庫語料10%的樣本

from nltk.corpus import treebank
t = treebank.parsed_sents('wsj_0001.mrg')[0]
print t
(S
  (NP-SBJ
    (NP (NNP Pierre) (NNP Vinken))
    (, ,)
    (ADJP (NP (CD 61) (NNS years)) (JJ old))
    (, ,))
  (VP
    (MD will)
    (VP
      (VB join)
      (NP (DT the) (NN board))
      (PP-CLR (IN as) (NP (DT a) (JJ nonexecutive) (NN director)))
      (NP-TMP (NNP Nov.) (CD 29))))
  (. .))
def filter(tree):    #搜尋樹庫找出句子的補語
    child_nodes = [child.label for child in tree if isinstance(child, nltk.Tree)]
    #print tree.label
    #print [t for t in tree if tree.label == 'NP']
    return (tree.label == 'VP') and ('S' in child_nodes)
from nltk.corpus import treebank
[subtree for tree in treebank.parsed_sents()
         for subtree in tree.subtrees(filter)]
entries = nltk.corpus.ppattach.attachments('training')
table = nltk.defaultdict(lambda: nltk.defaultdict(set))
for entry in entries:
    key = entry.noun1 + '-' + entry.prep + '-' + entry.noun2
    table[key][entry.attachment].add(entry.verb)
for key in sorted(table):
    if len(table[key]) > 1:
        print key, 'N:', sorted(table[key]['N']), 'V:', sorted(table[key]['V'])
nltk.corpus.sinica_treebank.parsed_sents()[3450].draw()  #中央研究院樹庫語料

#有害的歧義

歧義文法

#加權文法

處理歧義是開發覆蓋廣泛的解析器的主要任務。圖表解析器提高了計算同一個句子的多個分析的效率,但它們仍然會因可能的分析數量過多而不堪重負。加權文法和概率分析演算法為這些問題提供了有效的解決方案

def give(t):
    return t.label == 'VP' and len(t) > 2 and t[1].label == 'NP' \
           and (t[2].label == 'PP-DTV' or t[2].label == 'NP') \
           and ('give' in t[0].leaves() or 'gave' in t[0].leaves())
def sent(t):
    return ' '.join(token for token in t.leaves() if token[0] not in '*-0')
def print_node(t, width):
    output = "%s %s: %s / %s: %s" %\
        (sent(t[0]), t[1].label, sent(t[1]), t[2].label, sent(t[2]))
    if len(output) > width:
        output = output[:width] + "..."
    print output
for tree in nltk.corpus.treebank.parsed_sents():
    for t in tree.subtrees(give):
        print_node(t, 72)

#概率上下文無關文法(PCFG)

grammar = nltk.parse_pcfg("""
S    -> NP VP          [1.0]
VP   -> TV NP          [0.4]
VP   -> IV             [0.3]
VP   -> DatV NP NP     [0.3]
TV   -> 'saw'          [1.0]
IV   -> 'ate'          [1.0]
DatV -> 'gave'         [1.0]
NP   -> 'telescopes'   [0.8]
NP   -> 'Jack'         [0.2]
""")

七 深入閱讀