python自然語言處理學習筆記(八)—— 句法分析
前面的章節重點關注詞:如何識別它們,分析它們的結構,分配給他們詞彙類別,以及獲得它們的含義。我們還看到了如何識別詞序列或n-grams中的模式。然而,這些方法只觸碰到支配句子的複雜約束的表面。我們需要一種方法處理自然語言中顯著的歧義。我們還需要能夠應對這樣一個事實,句子有無限的可能,而我們只能寫有限的程式來分析其結構和發現它們的含義。
本章的目的是要回答下列問題:
我們如何使用形式化語法來描述無限的句子集合的結構?
我們如何使用句法樹來表示句子結構?
語法分析器如何分析一個句子並自動構建句法樹?
一路上,我們將覆蓋英語句法的基礎,並看到句子含義有系統化的一面,只要我們確定了句子結構,將更容易捕捉。
PS:書中的講解順序個人感覺比較難以理解,下面我會以自己的理解順序來重新調整
一、文法簡述
文法(語法)是用於描述語言的語法結構的形式規則。任何一種語言都有它自己的文法,我們最常接觸的文法自然語言裡有主謂賓這樣的文法一樣。(文法好像還分為句法和詞法,不去糾結這個,我們正常來說都是在處理句法)
使用文法有很多顯而易見的好處(畢竟大家都是有9年義務教育的人,都懂的),但在計算機中進行文法分析還需要解決兩個主要的問題,其一是文法在計算機中的表達與儲存方法,以及語料資料集;其二是文法解析的演算法。
1. 文法在計算機中的表達與儲存方法
在計算機中,我們可以用樹狀結構圖來表示,如下圖所示,S表示句子;NP、VP、PP是名詞、動詞、介詞短語(短語級別);N、V、P分別是名詞、動詞、介詞。
實際儲存的時候上述的樹可以表示為(S (NP (N Boeing)) (VP (V is) (VP (V located) (PP (P in) (NP (N Seattle))))))。
同時,網際網路上已經有成熟的、手工標註的語料資料集,例如The Penn Treebank Project (Penn Treebank II Constituent Tags)。
2. 文法解析的演算法
如何描述文法,有兩種主流觀點,其中一種是短語結構文法,英文術語是:Constituency = phrase structure grammar = context-free grammars (CFGs)。
這種短語語法用固定數量的rule分解句子為短語和單詞、分解短語為更短的短語或單詞等更小的單元。一個是取自WSJ語料庫的短語結構樹示例:
另一種是依存結構,用單詞之間的依存關係來表達語法。如果一個單詞修飾另一個單詞,則稱該單詞依賴於另一個單詞:
這一部分是接下來的重點
二、上下文無關文法(Context-Free Grammer)
CFG是一個四元組:G =(N,T,P,S),其中
- N是非終結符(Nonterminals)的有限集合
- T是終結符(Terminals)的有限集合,且N∩T=Φ
- P是產生式(Productions)的有限集合,形如:A→α,其中A∈N(左部),α∈(N∪T)*(右部),若α=ε,則稱A→ε為空產生式(也可以記為A →)
- S是非終結符,稱為文法的開始符號(Start symbol)
使用CFG可以很快速準確地定義簡單的算術表示式,例如N = {E} T = {+,*,(,),-,id} S = E
四元組,S = E
表明文法從E開始,也就是WSJ語料庫的短語結構樹中的S
,那麼產生式有這幾種:E → E + E; E → E * E; E →(E); E → -E; E → id
。
抽象地數學表示是這樣的,簡單來說,其實N
就是就是NP、VP、PP和N等的集合,T
就是我們的單詞。
定義這樣的四元組,主要是為了使用分析樹表示文法,也就是我們上面所看到的樹的結構。
分析樹的定義:
- 根由開始符號所標記
- 每個葉子由一個終結符、非終結符、或ε標記
- 每個內部結點由一個非終結符標記
- 若A是某內部節點的標記,且X1,X2,…,Xn是該節點從左到右所有孩子的標記,則A→X1X2…Xn是一個產生式。若A→ε,則標記為A的結點可以僅有一個標記為ε的孩子
其實拋開這些文縐縐的定義,我覺得最重要的一點就是:要求產生式的左部有且僅有一個非終結符
1. 遞迴下降解析器
一種最簡單的分析器將一個文法作為如何將一個高層次的目標分解成幾個低層次的子目標的規範來解釋。頂層的目標是找到一個 S。S→NP VP 產生式允許分析器替換這個目標為兩個子目標:找到一個 NP,然後找到一個 VP。每個這些子目標都可以再次被子目標的子目標替代,使用左側有 NP 和 VP 的產生式。最終,這種擴張過程達到子目標,如找到詞 telescope。這樣的子目標可以直接與輸入序列比較,如果下一個單詞匹配就取得成功。如 果沒有匹配,分析器必須備份,並嘗試其它選擇:
import nltk
from nltk import CFG
grammar1 = nltk.CFG.fromstring("""
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"
""")
rd_parser = nltk.RecursiveDescentParser(grammar1)
sent = 'Mary saw a dog'.split()
for t in rd_parser.parse(sent):
print(t)
可以呼叫nltk.app.rdparser()
來檢視分析過程:
遞迴下降分析是一種自上而下分析。自上而下分析器在檢查輸入之前先使用文法預測輸 入將是什麼。
三個主要缺點:
- 左遞迴產生式:NP-> NP PP 會陷入死迴圈
- 處理不符合句子的詞和結構時候浪費時間
- 回溯過程過重會丟掉計算過的分析,重新計算
2. 移進-歸約解析器
移進-歸約分析器是一種自下而上分析器,它嘗試找到對應文法產生式右側的詞和短語的序列,用左側的替換它們,直到整個句子歸約為一個 S。
移位-規約分析器反覆將下一個輸入詞推到堆疊,如果堆疊上的前 n 項,匹配一些產生式的右側的 n 個專案,那麼就把它們彈出棧,並把產生式左邊的專案壓入棧。這種替換前 n 項為一項的操作就是規約操作。此操作只適用於堆疊的頂部;規約棧中的專案必須在後面的專案被壓入棧之前做。當所有的輸入都使用過,堆疊中只剩餘一個專案,也就是一顆分析樹作為它的根的 S 節點時,分析器完成。移位-規約分析器通過上述過程建立一顆分析樹。每次彈出堆疊 n 個專案,它就將它們組合成部分的分析樹,然後將這壓回推棧:
sr_parse = nltk.ShiftReduceParser(grammar1)
for t in sr_parse.parse(sent):
print(t)
兩個缺點:
- 由於堆疊的特殊性,只能找到一種解析
- 不能保證一定能找到解析
3. 左角落分析器
遞迴下降分析器的問題之一是當它遇到一個左遞迴產生式時,會進入無限迴圈。這是因為它盲目應用文法產生式而不考慮實際輸入的句子。左角落分析器是自下而 上與自上而下方法的混合體。
左角落分析器是一個帶自下而上過濾的自上而下的分析器。不像普通的遞迴下降分析器,它不會陷入左遞迴產生式的陷阱。在開始工作之前,左角落分析器預處理上下文無關文法建立一個表,其中每行包含兩個單元,第一個存放非終結符,第二個存放那個非終結符可 能的左角落的集合
分析器每次考慮產生式時,它會檢查下一個輸入詞是否與左角落表格中至少一種非終結符的類別相容。
三、依存關係和依存文法
依存文法存在一個共同的基本假設:文法結構本質上包含詞和詞之間的依存(修飾)關係。一個依存關係連線兩個詞,分別是核心詞( head)和依存詞( dependent)。依存關係可以細分為不同的型別,表示兩個詞之間的具體句法關係。
依存關係是一個核心詞與它的依賴之間的二元對稱關係。一個句子的核心詞通常是動詞,所有其他詞要麼依賴於核心詞,要麼依賴路徑與它聯通。
依存關係表示是一個加標籤的有向圖,其中節點是詞彙項,加標籤的弧表示依賴關係, 從中心詞到依賴。
依存文法分析標註關係 (共14種) 及含義如下:
90年代的文法分析論文99%都是短語結構樹,但後來人們發現依存文法樹標註簡單,parser準確率高,所以後來(特別是最近十年)基本上就是依存文法樹的天下了(至少80%)。
目前研究主要集中在資料驅動的依存文法分析方法,即在訓練例項集合上學習得到依存文法分析器,而不涉及依存語法理論的研究。資料驅動的方法的主要優勢在於給定較大規模的訓練資料,不需要過多的人工干預,就可以得到比較好的模型。因此,這類方法很容易應用到新領域和新語言環境。資料驅動的依存文法分析方法主要有兩種主流方法:基於圖( graph-based)的分析方法和基於轉移( transition-based)的分析方法
1. 基於圖的依存句法分析方法
基於圖的方法將依存句法分析問題看成從完全有向圖中尋找最大生成樹的問題。一棵依存樹的分值由構成依存樹的幾種子樹的分值累加得到。根據依存樹分值中包含的子樹的複雜度,基於圖的依存分析模型可以簡單區分為一階和高階模型。 高階模型可以使用更加複雜的子樹特徵,因此分析準確率更高,但是解碼演算法的效率也會下降。基於圖的方法通常採用基於動態規劃的解碼演算法,也有一些學者採用柱搜尋(beam search)來提高效率。學習特徵權重時,通常採用線上訓練演算法,如平均感知器( average dperceptron)。
目前基於圖的方法的句法分析演算法主要有自頂向下(Top Down),自底向上(Bottom Up),最大生成樹(Spanning Tree)的方法。
例如在使用最大熵演算法進行依存句法分析時就是生成一系列句法樹,使用最大熵等模型去計算單條依存邊的概率,從裡面挑選出概率最大的那一棵作為輸出。
具體可以參考:基於最大熵的依存句法分析
2. 基於轉移的依存句法分析方法
基於轉移的方法將依存樹的構成過程建模為一個動作序列,將依存分析問題轉化為尋找最優動作序列的問題。 早期,研究者們使用區域性分類器(如支援向量機等)決定下一個動作。近年來,研究者們採用全域性線性模型來決定下一個動作,一個依存樹的分值由其對應的動作序列中每一個動作的分值累加得到。特徵表示方面,基於轉移的方法可以充分利用已形成的子樹資訊,從而形成豐富的特徵,以指導模型決策下一個動作。模型通過貪心搜尋或者柱搜尋等解碼演算法找到近似最優的依存樹。和基於圖的方法類似,基於轉移的方法通常也採用線上訓練演算法學習特徵權重
總的來說,基於轉移的依存句法分析方法是基於動作(或稱轉移)和一個分類器實現的,仿照人類從左到右的閱讀順序,其不斷地讀入單詞,根據該單詞和已構建的句法子樹等資訊建立分類模型,分類模型輸出當前狀態下的最佳動作,然後分析器根據最佳動作“拼裝”句法樹
目前基於轉移的依存句法分析方法主要分為基於棧(Stack Based)和基於列表(List Based)兩類,其中基於棧的又分為arc-standard演算法和arc-eager演算法。
補充知識點:投射和非投射
投射性:如果詞p依存於詞q,那麼p和q之間的任意詞r就不能依存到p和q所構成的跨度之外
簡單來說就是任意構成依存的兩個單詞構成一個籠子,把它們之間的所有單詞囚禁在這個籠子裡,內部的詞的依存關係只能在這個籠子裡,也就是說不存在交叉的依存弧,如下圖所示:
3. 多模型融合的依存句法分析方法
基於圖和基於轉移的方法從不同的角度解決問題,各有優勢。基於圖的模型進行全域性搜尋但只能利用有限的子樹特徵,而基於轉移的模型搜尋空間有限但可以充分利用已構成的子樹資訊構成豐富的特徵。詳細比較發現,這兩種方法存在不同的錯誤分佈。因此,研究者們使用不同的方法融合兩種模型的優勢,常見的方法有:stacked learning;對多個模型的結果加權後重新解碼(re-parsing);從訓練語料中多次抽樣訓練多個模型(bagging)。
四、額外的筆記——語義依存分析
語義依存分析 (Semantic Dependency Parsing, SDP),分析句子各個語言單位之間的語義關聯,並將語義關聯以依存結構呈現。 使用語義依存刻畫句子語義,好處在於不需要去抽象詞彙本身,而是通過詞彙所承受的語義框架來描述該詞彙,而論元的數目相對詞彙來說數量總是少了很多的。語義依存分析目標是跨越句子表層句法結構的束縛,直接獲取深層的語義資訊。 例如以下三個句子,用不同的表達方式表達了同一個語義資訊,即張三實施了一個吃的動作,吃的動作是對蘋果實施的。
語義依存分析不受文法結構的影響,將具有直接語義關聯的語言單元直接連線依存弧並標記上相應的語義關係。這也是語義依存分析與文法依存分析的重要區別。
再看一下三個句子的句法依存分析和語義依存分析的對比:
從上邊的對比可以看出,雖然三個句子擁有不同的句子結構, 產生了不同的句法分析結果, 但是三個句子中語言單元之間的語義關係並沒有發生變化, 從"吃"這個詞來看, 它的主體, 客體...都沒有發生變化。
再看一個例子:
如上例對比了句法依存和語義分析的結果,可以看到兩者存在兩個顯著差別:
句法依存某種程度上更重視非實詞(如介詞)在句子結構分析中的作用,而語義依存更傾向在具有直接語義關聯的實詞之間建立直接依存弧,非實詞作為輔助標記存在
兩者依存弧上標記的語義關係完全不同,語義依存關係是由論元關係引申歸納而來,可以用於回答問題,如我在哪裡喝湯,我在用什麼喝湯,誰在喝湯,我在喝什麼。但是句法依存卻沒有這個能力
語義依存與語義角色標註之間也存在關聯,語義角色標註只關注句子主要謂詞的論元及謂詞與論元之間的關係
,而語義依存不僅關注謂詞與論元的關係,還關注謂詞與謂詞之間、論元與論元之間、論元內部的語義關係
。語義依存對句子語義資訊的刻畫更加完整全面。
語義依存關係分為三類,分別是主要語義角色,每一種語義角色對應存在一個巢狀關係和反關係;事件關係,描述兩個事件間的關係;語義依附標記,標記說話者語氣等依附性資訊。
五、歧義
一個眾所周知的關於歧義例子如下所示,來自 Groucho Marx 的電影,Animal Crac kers (1930):
While hunting in Africa, I shot an elephant in my pajamas. How an elephant got into my pajamas I’ll never know.
雖然我一直get不到這個歧義,不過歧義也很好理解,就是一句話有不同的理解,用我們之前的特徵方法很難解決歧義的問題,但文法分析可以很好地解決:
參考
相關文章
- 自然語言處理NLP(8)——句法分析b:完全句法分析自然語言處理
- 自然語言處理常用資源筆記分享自然語言處理筆記
- 精通Python自然語言處理 3 :形態學Python自然語言處理
- 自然語言處理NLP(7)——句法分析a:Chomsky(喬姆斯基)形式文法自然語言處理
- 機器學習工作坊 - 自然語言處理機器學習自然語言處理
- 自然語言處理中的遷移學習(下)自然語言處理遷移學習
- 自然語言處理中的遷移學習(上)自然語言處理遷移學習
- 精通Python自然語言處理 2 :統計語言建模Python自然語言處理
- 精通Python自然語言處理 1 :字串操作Python自然語言處理字串
- 《NLP漢語自然語言處理原理與實踐》學習四自然語言處理
- 自然語言處理(NLP)系列(一)——自然語言理解(NLU)自然語言處理
- HanLP 自然語言處理 for nodejsHanLP自然語言處理NodeJS
- 自然語言處理NLP(四)自然語言處理
- 自然語言處理(NLP)概述自然語言處理
- 《Python自然語言處理實戰》連結表Python自然語言處理
- hanlp自然語言處理包的基本使用--pythonHanLP自然語言處理Python
- 《深度學習進階:自然語言處理》中的網址深度學習自然語言處理
- Python自然語言處理工具Python自然語言處理
- python呼叫自然語言處理工具hanlp記錄Python自然語言處理HanLP
- Python自然語言處理實戰(1):NLP基礎Python自然語言處理
- 如何用Python處理自然語言?(Spacy與Word Embedding)Python
- [譯] 自然語言處理真是有趣!自然語言處理
- 自然語言處理:分詞方法自然語言處理分詞
- 突破!自然語言強化學習(NLRL):一個可處理語言反饋的強化學習框架強化學習框架
- 牛津大學xDeepMind自然語言處理 第13講 語言模型(3)自然語言處理模型
- 自然語言處理背後的資料科學自然語言處理資料科學
- 基於圖深度學習的自然語言處理方法和應用深度學習自然語言處理
- Go語言核心36講(Go語言進階技術八)--學習筆記Go筆記
- 使用 Python+spaCy 進行簡易自然語言處理Python自然語言處理
- Python 自然語言處理(基於jieba分詞和NLTK)Python自然語言處理Jieba分詞
- 自然語言處理與情緒智慧自然語言處理
- Pytorch系列:(六)自然語言處理NLPPyTorch自然語言處理
- 自然語言處理的最佳實踐自然語言處理
- 自然語言處理之jieba分詞自然語言處理Jieba分詞
- 人工智慧 (06) 自然語言處理人工智慧自然語言處理
- 自然語言處理NLP快速入門自然語言處理
- 配置Hanlp自然語言處理進階HanLP自然語言處理
- 史丹佛自然語言處理習題課1——緒論自然語言處理