我目前正在开展涉及NLP的项目。我已经实现了Jurafsky和Martin中给出的CKY标识符(第450页的算法)。这样生成的表实际上将非终结符存储在表中(而不是通常的布尔值)。但是,我得到的唯一问题是检索解析树。
以下是我的CKY标识符的作用:
这是我的语法
S -> NP VP
S -> VP
NP -> MODAL PRON | DET NP | NOUN VF | NOUN | DET NOUN | DET FILENAME
MODAL -> 'MD'
PRON -> 'PPSS' | 'PPO'
VP -> VERB NP
VP -> VERB VP
VP -> ADVERB VP
VP -> VF
VERB -> 'VB' | 'VBN'
NOUN -> 'NN' | 'NP'
VF -> VERB FILENAME
FILENAME -> 'NN' | 'NP'
ADVERB -> 'RB'
DET -> 'AT'
这是算法:
for j from i to LENGTH(words) do
table[j-1,j] = A where A -> POS(word[j])
for i from j-2 downto 0
for k from i+1 to j-1
table[i,j] = Union(table[i,j], A such that A->BC)
where B is in table[i,k] and C is in table[k,j]
这就是我的解析表在填充之后的样子:
现在我知道,因为S驻留在[0,5]中,字符串已被解析,而对于k = 1(根据Martin和Jurafsky中给出的算法),我们有S - >表[0] [2]表[2] [5] 即S - > NP VP
我得到的唯一问题是我能够检索所使用的规则,但是它们是混乱的格式,即不是基于它们在解析树中的外观。有人可以建议一个算法来检索正确的解析树吗?
三江源。
答案 0 :(得分:3)
你应该以递归的方式访问你桌子的单元格并以与你对S节点相同的方式展开它们,直到所有东西都是一个终端(所以你没有其他东西可以展开)。在您的示例中,您首先转到单元格[0] [2];这是一个终端,你不必做任何事情。接下来转到[2] [5],这是[2] [3]和[3] [5]制作的非终端。你访问[2] [3],它是一个终端。 [3] [5]是一个非终端,由两个终端制成。你完成了。这是Python的演示:
class Node:
'''Think this as a cell in your table'''
def __init__(self, left, right, type, word):
self.left = left
self.right = right
self.type = type
self.word = word
# Declare terminals
t1 = Node(None,None,'MOD','can')
t2 = Node(None,None,'PRON','you')
t3 = Node(None,None,'VERB', 'eat')
t4 = Node(None,None,'DET', 'a')
t5 = Node(None,None,'NOUN','flower')
# Declare non-terminals
nt1 = Node(t1,t2, 'NP', None)
nt2 = Node(t4,t5, 'NP', None)
nt3 = Node(t3,nt2,'VP', None)
nt4 = Node(nt1,nt3,'S', None)
def unfold(node):
# Check for a terminal
if node.left == None and node.right == None:
return node.word+"_"+node.type
return "["+unfold(node.left)+" "+unfold(node.right)+"]_"+node.type
print unfold(nt4)
输出:
[[can_MOD you_PRON]_NP [eat_VERB [a_DET flower_NOUN]_NP]_VP]_S