#!/usr/bin/env python
# coding: utf-8

8.5 依存关系 和 依存文法

·依存文法:一个中心词(通常是动词)与其从属之间的二元非对称关系。(集中关注的是词与其他词之间的关系)
·如下nltk依存文法编码的一种方式,只能捕捉依存关系信息。
# import nltk
# groucho_dep_grammar = nltk.parse_dependency_grammar('''
# 'shot' -> 'I' | 'elephant' | 'in'
# 'elephant' -> 'an' | 'in'
# 'in' -> 'pajamas'
# 'pajamas' -> 'my'
# ''')


# In[ ]:


# nltk.parse_dependency_grammar 改用了 DependencyGrammar.fromstring。
from nltk.grammar import DependencyGrammar
from nltk.parse import (
    DependencyGraph,
    ProjectiveDependencyParser,       #  这个是有的!!!!!!
    NonprojectiveDependencyParser,
    )


# In[ ]:


dep_grammar = DependencyGrammar.fromstring(
    """
    'shot' -> 'I' | 'elephant' | 'in'
    'elephant' -> 'an' | 'in'
    'in' -> 'pajamas' 
    'pajamas' -> 'my'
    """
    )
print(dep_grammar)


# In[ ]:


# 依存关系图是一个投影


# In[ ]:


#  演示了dep_grammar如何使用另一种替代方法来捕捉附着歧义
pdp = nltk.ProjectiveDependencyParser(dep_grammar)

sent = 'I shot an elephant in my pajamas'.split()

trees = pdp.parse(sent)

# for tr in trees:
#     print(tr)  
#ProjectiveDependencyParser  返回的是generator,所以必须重复下面行,才可以画出图。
# trees = ProjectiveDependencyParser(dep_grammar).parse(sent)
for tree in trees:
    print(tree)
    print(tree.draw())

1、配价 与 词汇

·及物动词TV,子类别
·修饰语:介词短语、形容词和副词;补语:受中心词选择。

2、扩大规模

·小型文法扩展到大型语料库非常困难。
·歧义会随着覆盖范围的扩大而增加。
·为几种语言开发基于规则的文法的一些大的合作项目:
    (1)词汇功能语法(LFG)Pargram项目;
    (2)中心词驱动语法结构文法LinGo矩阵框架;
    (3)领接着文法XTAG的词汇化树项目。

8.6 文法开发

1、树库 和 文法

# In[ ]:


from nltk.corpus import treebank

t = treebank.parsed_sents('wsj_0001.mrg')[0]
print(t)


# In[ ]:


#  搜索树库找出句子的补语
def filter(tree):
    child_nodes = [child.label() for child in tree
                    if isinstance(child, nltk.Tree)]
    return (tree.label() == 'VP') and ('S' in child_nodes)

[subtree for tree in treebank.parsed_sents()
         for subtree in tree.subtrees(filter)]


·PP附着语料库:nltk.corpus.ppattach是另一个有关特别动词配价的信息源

# In[ ]:


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)


# In[ ]:


for key in sorted(table):
    if len(table[key]) > 1:
        print(key, 'N:', sorted(table[key]['N']), 'V:', sorted(table[key]['V']))


# In[6]:


nltk.corpus.sinica_treebank.parsed_sents()[3450].draw()

2、有害的歧义

# In[20]:


import nltk
# 'fish'句子的玩具文法
grammar = nltk.CFG.fromstring('''
    S -> NP V NP
    NP -> NP Sbar
    Sbar -> NP V
    NP -> 'fish'
    V -> 'fish'
''')


# In[21]:


tokens = ['fish'] * 5
cp = nltk.ChartParser(grammar)
for tree in cp.parse(tokens):
    print(tree)
    
·即使某句话不可能(the a are of me),但它仍是符合语法的;
·看上去没有歧义的句子,结果却出现没有想到的其他读法,导致低效率!
为此,出现了概率分析。

3、加权文法

# In[33]:


# 宾州树库样本中的give和gave用法

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())
 

# In[34]:


def sent(t):
    return ' '.join(token for token in t.leaves() if token[0] not in '*-0')


# In[35]:


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)


# In[36]:


for tree in nltk.corpus.treebank.parsed_sents():
    for t in tree.subtrees(give):
        print_node(t, 72)


# In[ ]:


·概率上下文无关文法(PCFG)


# In[51]:


# 定义一个概率上下文无关文法(PCFG)


# nltk.parse_pcfg 改成了 nltk.PCFG.fromstring
grammar = nltk.PCFG.fromstring('''      
    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]
''')


# In[49]:


print(grammar)


# In[52]:


viterbi_parser = nltk.ViterbiParser(grammar)


# In[61]:


sent = 'Jack saw telescopes'.split()
for i in viterbi_parser.parse(sent):
    print(i.draw(), i)
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐