如何在NLTK中基于PCFG的概率生成符合分布的句子样本?
基于NLTK的PCFG按概率抽样生成句子样本
NLTK自带的generate()方法对PCFG文法只会枚举所有可能的唯一句子,不会根据产生式的概率权重进行重复抽样。比如你给出的例子:
from nltk import PCFG from nltk.parse.generate import generate pcfg = PCFG.fromstring("S -> 'a' [0.7] | 'b' [0.3]") print(list(generate(pcfg, n=10))) # 输出: [['a'], ['b']]
即便指定n=10,也只会返回所有可能的句子各一次,无法得到按概率分布的抽样结果。
解决方案:自定义概率抽样生成函数
NLTK没有内置的PCFG抽样生成工具,但可以自己实现一个基于概率权重递归选择产生式的生成逻辑,核心步骤是:
- 针对当前非终结符,提取其所有产生式及对应概率
- 按概率权重随机选择一条产生式
- 递归展开产生式中的符号,直到全部为终结符
完整代码实现
import random from nltk import PCFG def sample_pcfg(pcfg, start_symbol=None): """基于PCFG概率权重随机生成单句""" start = start_symbol or pcfg.start() # 获取当前非终结符的所有产生式与对应概率 productions = pcfg.productions(lhs=start) probs = [prod.prob() for prod in productions] # 按概率随机选一条产生式 selected_prod = random.choices(productions, weights=probs, k=1)[0] sentence = [] for symbol in selected_prod.rhs(): if symbol.is_terminal(): sentence.append(symbol) else: # 递归展开非终结符 sentence.extend(sample_pcfg(pcfg, symbol)) return sentence def sample_pcfg_multiple(pcfg, n, start_symbol=None): """生成n个按PCFG概率抽样的句子""" return [sample_pcfg(pcfg, start_symbol) for _ in range(n)]
测试示例
# 测试简单文法 pcfg = PCFG.fromstring("S -> 'a' [0.7] | 'b' [0.3]") samples = sample_pcfg_multiple(pcfg, n=10) print(samples) # 示例输出(符合概率分布,a占比约70%): # [['a'], ['a'], ['a'], ['a'], ['a'], ['a'], ['a'], ['b'], ['b'], ['b']] # 测试多层复杂文法 complex_pcfg = PCFG.fromstring(""" S -> NP VP [1.0] NP -> 'I' [0.6] | 'You' [0.4] VP -> V NP [0.8] | V [0.2] V -> 'like' [0.7] | 'hate' [0.3] """) samples = sample_pcfg_multiple(complex_pcfg, n=5) print(samples) # 示例输出: # [['I', 'like', 'You'], ['I', 'hate'], ['You', 'like', 'I'], ['I', 'like', 'I'], ['You', 'hate', 'You']]
内容的提问来源于stack exchange,提问作者Albert Gevorgyan
相关产品推荐
相关产品推荐

