非深度学习方案下,如何为NLTK CCG词典生成明确论元数量的动词词条?
非深度学习方案下,如何为NLTK CCG词典生成明确论元数量的动词词条?
看起来你在半自动构建NLTK CCG词典的过程中,卡在了动词论元数量的分类上——毕竟NLTK的POS标签只关心动词的时态形式(VB/VBD/VBG这些),完全不区分它是不及物、及物还是双及物,这确实挺头疼的!下面给你几个不需要深度学习的实用方案:
一、借助预标注词汇资源映射
你可以用已经标注好动词论元结构的本地词汇资源(比如NLTK自带的WordNet),直接把动词映射到对应的CCG范畴。WordNet的动词词条会标注子类别(不及物/单及物/双及物),你可以写个简单的脚本完成映射:
from nltk.corpus import wordnet from nltk import pos_tag def get_ccg_verb_category(verb): # 把NLTK POS标签转成WordNet兼容的词性标记 pos_map = { 'VB': wordnet.VERB, 'VBD': wordnet.VERB, 'VBG': wordnet.VERB, 'VBN': wordnet.VERB, 'VBP': wordnet.VERB, 'VBZ': wordnet.VERB } # 获取动词的POS标签,匹配WordNet义项 verb_pos = pos_tag([verb])[0][1] synsets = wordnet.synsets(verb, pos=pos_map.get(verb_pos, wordnet.VERB)) if not synsets: return None # 无匹配义项时返回空 # 取第一个义项(通常是最常用的)的框架信息 first_lemma = synsets[0].lemmas()[0] frame_ids = first_lemma.frame_ids() # WordNet框架ID对应论元结构:1=不及物,2=单及物,3=双及物 if 1 in frame_ids: return 'VP' elif 2 in frame_ids: return 'TV :: VP/NP' elif 3 in frame_ids: return 'DTV :: TV/NP' else: return 'TV :: VP/NP' # 默认单及物 # 测试示例 print(get_ccg_verb_category('arrive')) # 输出 VP print(get_ccg_verb_category('cook')) # 输出 TV :: VP/NP print(get_ccg_verb_category('give')) # 输出 DTV :: TV/NP
注意:部分动词有多个义项,你可以调整逻辑,统计所有义项中出现最多的论元类型,进一步提高准确率。
二、基于句法规则的模式匹配
如果不想依赖外部词汇资源,你可以用NLTK的句法解析器( constituency或依存解析器),通过分析动词在句子中的搭配成分来判断论元数量:
- 动词后无名词短语(NP)宾语 → 不及物动词 →
VP - 动词后有1个NP宾语 → 单及物动词 →
TV :: VP/NP - 动词后有2个NP(或1个NP+介词引导的间接宾语) → 双及物动词 →
DTV :: TV/NP
示例代码(用NLTK的CoreNLP依存解析器,需本地启动CoreNLP服务):
from nltk.parse import CoreNLPParser # 初始化依存解析器(假设CoreNLP服务运行在本地9000端口) dep_parser = CoreNLPParser(url='http://localhost:9000', tagtype='pos') def judge_verb_arg_count(sentence): parsed_triples = next(dep_parser.raw_parse(sentence)) verb_result = None for (gov, rel, dep) in parsed_triples: # 找到句子中的动词 if gov[1].startswith('VB'): obj_count = 0 # 统计直接宾语(dobj)和间接宾语(iobj)的数量 for (g, r, d) in parsed_triples: if g == gov and r in ['dobj', 'iobj']: obj_count += 1 # 根据宾语数量映射到CCG范畴 if obj_count == 0: verb_result = (gov[0], 'VP') elif obj_count == 1: verb_result = (gov[0], 'TV :: VP/NP') elif obj_count >= 2: verb_result = (gov[0], 'DTV :: TV/NP') break return verb_result # 测试示例 print(judge_verb_arg_count('He arrives home')) # 输出 ('arrives', 'VP') print(judge_verb_arg_count('She cooks delicious dinner')) # 输出 ('cooks', 'TV :: VP/NP') print(judge_verb_arg_count('I give him a new book')) # 输出 ('give', 'DTV :: TV/NP')
这个方法需要你用一定规模的语料测试规则,比如处理“give sth to sb”这类介词引导的间接宾语场景,但胜在完全基于句法结构,不需要额外词汇库。
三、优化你的“多候选验证”方案
如果上面两种方法都不适用,你可以优化原本的思路:给每个动词生成三个候选CCG范畴,然后用NLTK的CCG解析器验证,选择能生成合法解析树的范畴。这里有两个小技巧提升效率:
- 优先尝试高频范畴:比如大部分动词是单及物,先尝试
TV :: VP/NP,再试VP,最后试DTV :: TV/NP,减少无效验证。 - 多句验证:用多个包含该动词的句子测试,比如某个动词在3个句子里都只能用
TV范畴解析成功,就确定它属于TV,避免单句歧义影响结果。
备注:内容来源于stack exchange,提问作者SubFunction
相关产品推荐
相关产品推荐

