资讯详情

numpy-ml N-gram 平滑模型实战指南:Laplace、Additive/Lidstone 与 Good-Turing 平滑的原理与 NumPy 实现

📅 2026/9/21 2:30:50 | 华诺云谱 👁 阅读
numpy-ml N-gram 平滑模型实战指南:Laplace、Additive/Lidstone 与 Good-Turing 平滑的原理与 NumPy 实现
机器学习人工智能【免费下载链接】numpy-mlMachine learning, in numpy项目地址https://gitcode.com/gh_mirrors/nu/numpy-ml点击查看免费下载N-gram 语言模型是统计自然语言处理的基础组件其核心难题在于稀疏数据下的概率估计训练语料中大量合法的 N-gram 从未出现若直接采用最大似然估计未出现序列的概率会被错误地估计为零。本文基于 numpy-ml 仓库的 numpy_ml.ngram.rst 文档系统讲解 Laplace 平滑、Additive/Lidstone 平滑与 Good-Turing 平滑三种经典平滑技术的数学原理并结合仓库源码 numpy_ml/ngram/ngram.py 与其测试用例说明它们的 NumPy 实现、调用方式与效果差异。读完本文你将掌握平滑概率公式的推导、三个模型类的完整 API 用法以及如何用困惑度perplexity评估和比较不同平滑策略。本文讨论的平滑模型全部收敛于 numpy-ml 的numpy_ml.ngram子模块其模块结构如下numpy_ml/ngram/ngram.py三个模型类与共享基类的完整实现numpy_ml/ngram/__init__.py从ngram.py导出全部类numpy_ml/ngram/README.md模块概述与效果图numpy_ml/tests/test_ngram.py以 NLTK 为基准的对照测试numpy_ml/plots/ngram_plots.py平滑效果可视化脚本。一、为什么需要平滑稀疏数据下的概率估计问题在 N-gram 模型中一个词序列w_i^j (w_i, w_{i1}, ..., w_j)即长度为j - i的 N-gram的条件概率通常由语料中的经验频次直接估计。然而真实语料永远无法覆盖所有可能的词组合随着 N 增大可能的 N-gram 数量呈指数增长而训练数据只是其中极小一部分。docs/numpy_ml.ngram.rst开篇即点明主题处理 N-gram 模型时平滑smoothing指的是调整经验概率估计以应对数据不足的做法。平滑的本质是劫富济贫从高频 N-gram 的概率质量中分出一部分转移给低频或未出现的 N-gram避免零概率同时尽量保持模型的整体概率分布合理。numpy-ml 在 numpy_ml/ngram/ngram.py 中通过抽象基类NGramBase统一了所有平滑模型的骨架。它接收四个超参数全部通过hyperparameters字典管理参数类型默认值含义Nint必填语言模型的最大上下文窗口长度词数训练时会计算 1, 2, ..., N 阶所有 N-gramunkboolTrue是否在语言模型中保留unk未知词标记filter_stopwordsboolTrue训练前是否过滤停用词filter_punctuationboolTrue训练前是否过滤标点NGramBase还提供了一批所有平滑模型共享的核心方法源码定义train(corpus_fp, vocabNone, encodingNone)统计语料中 N, N-1, ..., 1-gram 的计数结果存于self.counts、self.n_words、self.n_tokenscompletions(words, N)返回给定前缀下所有可能后继词及其对数概率generate(N, seed_words, n_sentences)用模型采样生成句子遇到eol结束一句perplexity(words, N)与cross_entropy(words, N)评估模型在测试序列上的表现。三个具体模型MLENGram、AdditiveNGram、GoodTuringNGram均继承自NGramBase只实现两个抽象方法log_prob与_log_ngram_prob抽象定义即整句对数概率与单个 N-gram 对数概率。这意味着三种平滑技术的差异最终只体现在_log_ngram_prob这一个函数的概率公式上——这是理解本模块架构的关键。二、Laplace 平滑加一平滑的朴素假设docs/numpy_ml.ngram.rst给出的第一种平滑技术是 Laplace 平滑也常被称为加一平滑。它的假设非常朴素认为语料中每个 N-gram 实际上都比观测到的计数多出现一次。设c(w_{i-n1}^i)为语料中 N-gramw_{i-n1}^i的经验计数|V|为语料中不重复 N-gram 的种类数词表大小则条件概率公式为p(w_i | w_{i-n1}^{i-1}) (1 c(w_{i-n1}^i)) / (|V| Σ_{w_i} c(w_{i-n1}^i))即分子加 1分母加上|V|以保证所有可能的下一词概率之和仍为 1。这样未出现在语料中的 N-gram 也能获得1 / (|V| ...)的非零概率。从文档可以看到Laplace 平滑对应的模型是AdditiveNGram——它是 Additive加性平滑在K 1时的特例因此没有独立的模型类这也解释了为什么文档的Models列表中 Laplace 平滑与 Additive 平滑指向同一个类AdditiveNGram。三、Additive / Lidstone 平滑一般化的加性平滑3.1 数学原理Laplace 平滑强行加 1 过于武断。AdditiveLidstone平滑将其推广为每个 N-gram 都比实际多出现k次其中k可以是任意非负值但通常取值在[0, 1]区间文档定义p(w_i | w_{i-n1}^{i-1}) (k c(w_{i-n1}^i)) / (k·|V| Σ_{w_i} c(w_{i-n1}^i))其中c(a)仍是 N-grama的经验计数|V|是语料中不重复 N-gram 的种类数。当k 0时退化为未平滑的最大似然估计k越大分配给未见事件unseen events的概率质量越多。3.2AdditiveNGram的源码实现AdditiveNGram的构造函数源码在基类参数之上新增了核心超参数K参数默认值说明K1加到每个观测上的伪计数pseudocount。K 1时即 Laplace 平滑K 0.5时称为期望似然估计expected likelihood estimation, ELE即 Jeffreys-Perks 法则文档与源码都强调了一个重要的概率论视角Additive 平滑的估计结果等价于在计数上施加对称 Dirichlet 先验参数为K后后验p(ngram_prob | counts)的期望值。也就是说K不是拍脑袋的调参量而是 Dirichlet 先验的强度参数。其核心概率计算实现于_log_ngram_prob源码def _log_ngram_prob(self, ngram): N len(ngram) K self.hyperparameters[K] counts, n_words, n_tokens self.counts, self.n_words[1], self.n_tokens[1] ctx ngram[:-1] num counts[N][ngram] K ctx_count counts[N - 1][ctx] if N 1 else n_words den ctx_count K * n_tokens return np.log(num / den) if den ! 0 else -np.inf对照公式可见分子是经验计数 K分母是上下文计数 K × 词表大小n_tokens。对于 bigramN2源码 docstring 给出了直观写法P(w_i | w_{i-1}) (A K) / (B K·V)其中A Count(w_{i-1}, w_i)B Σ_j Count(w_{i-1}, w_j)V |{w_j : Count(w_{i-1}, w_j) 0}|。这等价于假装每一个可能的 N-gram 序列都至少被观察过 K 次。3.3 已知缺陷文档与源码明确列出了 Additive 平滑的两个问题平等对待每个待预测词它对所有未见 N-gram 一视同仁地分配概率忽略了不同 N-gram 之间的差异可能给未见 N-gram 分配过多概率质量尤其当词表很大时K·|V|项会显著稀释已见 N-gram 的概率。这两点正是引入更精细的 Good-Turing 平滑的动机。四、Good-Turing 平滑按频率重新分配概率质量4.1 核心思想与公式Good-Turing 平滑比 Additive 平滑精细得多。它根据 N-gram 的具体出现频次决定平滑量将出现r1次的 N-gram 所占据的一部分概率空间划分出来分配给只出现r次的 N-gram文档定义。设g(x)为语料中出现恰好x次的 N-gram 个数即count-of-countsN为语料中 N-gram 的总数则出现r次的 N-gram 的调整计数为r* (r 1) · g(r 1) / g(r) p(w_{i-n1}^i | c(w_{i-n1}^i) r) r* / N直观理解高频 N-gram 的g(r1)与g(r)相近r* ≈ r调整很小而低频 N-gram 的计数被显著下调/上调被腾出的概率质量正好用于那些从未出现的 N-gram其总概率等于只出现一次 N-gram 的相对占比。4.2 大规模计数下的对数线性插值g(r)在高频区间会变得极其不可靠大数定律失效样本稀疏。numpy-ml 的GoodTuringNGram采用了 Gale 提出的 Simple Good-Turing 方案当经验估计不可靠时用一个对数线性幂律模型来平滑 count-of-counts。其核心逻辑在_calc_smoothed_counts源码中实现主要步骤为计算未见 N-gram 的总概率p0p0 NC(1, N) / Σ counts即只出现一次 N-gram 的相对占比源码拟合 count 模型调用_fit_count_models源码对每个 N 阶分别做 Church Gale (1991) 的 averaging transform然后用 numpy-ml 自带的LinearRegression拟合log(NC) ~ log(r)的对数线性关系log NC(r) b a·log r经验值与插值择优对每个计数C同时计算经验平滑计数count_emp (C1)·NC(C1)/NC(C)和对数线性插值count_interp用置信度阈值t conf·σ判断两者差异是否显著若|count_interp - count_emp| t则采用经验值否则切换到插值源码。GoodTuringNGram新增的唯一超参数是conf构造函数参数默认值说明conf1.96经验平滑计数标准差的乘子决定有多少数据点交由对数线性模型平滑。默认值1.96对应 95% 置信区间另外注意GoodTuringNGram重写了train方法源码在基类完成计数统计后额外调用_calc_smoothed_counts()预计算所有平滑计数并缓存因此后续概率查询不会重复拟合。在概率查询端_log_ngram_prob源码对已见 N-gram 使用平滑计数C*P(ngram) (1 - p0) · C* / T其中T为所有平滑计数之和归一化常数对未见 N-gram 则从p0中按未见种类数均分保证概率分布合法。4.3 基准文献docs/numpy_ml.ngram.rst在文末列出了两项权威参考文献也是 Good-Turing 平滑的理论依据Chen Goodman (1998). An empirical study of smoothing techniques for language modeling. Harvard CSG Technical Report TR-10-98Gale Sampson (1995). Good-Turing frequency estimation without tears. Journal of Quantitative Linguistics, 2(3), 217-237。五、训练、评估与生成完整 API 使用示例5.1 训练一个平滑 N-gram 模型所有模型都通过train(corpus_fp, vocabNone, encodingNone)训练corpus_fp指向一个换行分隔的文本语料文件基类文档。可选参数vocab传入numpy_ml.preprocessing.nlp.Vocabulary实例以限定词表此时词表外单词在unkTrue时映射为unk、unkFalse时被删除encoding支持utf-8、utf-8-sig、utf-16等常见编码。from numpy_ml.ngram import MLENGram, AdditiveNGram, GoodTuringNGram # 训练一个三元模型N3使用 K0.5ELE的 Additive 平滑 model AdditiveNGram(N3, K0.5, unkTrue, filter_stopwordsFalse, filter_punctuationFalse) model.train(corpus.txt, encodingutf-8-sig) # 训练后模型内部保存了 1-gram、2-gram、3-gram 的计数 print(sorted(model.counts[1].items(), keylambda x: -x[1])[:5]) print(model.n_words) # 每阶 N-gram 的总数 print(model.n_tokens) # 每阶不重复 N-gram 的种类数5.2 评估困惑度与交叉熵NGramBase内置了两个评估方法源码cross_entropy(words, N)H(W) -log p(W) / n其中n是W中 N-gram 的个数以自然对数底数 e计与编码 W 所需平均比特数成正比perplexity(words, N)PP(W) exp(H(W))。test_words [the, cat, sat, on, the, mat] pp model.perplexity(test_words, N3) ce model.cross_entropy(test_words, N3)文档强调最小化困惑度等价于最大化测试序列在模型下的概率它也可以理解为语言模型预测下一个词时的平均分支因子branching factor。数值越低模型对真实文本的拟合越好。5.3 补全与句子生成completions(words, N)返回给定前缀下所有候选后继词及其对数概率源码generate(N, seed_words, n_sentences)则基于这些分布随机采样生成句子句子以eol结束bol用作句首填充源码。# 查看 the 之后最可能的 5 个词 comps sorted(model.completions([the], N3), keylambda x: -x[1]) print(comps[:5]) # 用三元模型生成 5 个句子 model.generate(N3, seed_words[bol], n_sentences5)注意generate内部会对平滑概率做再归一化np.exp(probs) / np.exp(probs).sum()源码确保采样分布合法。六、正确性验证与 NLTK 的对照测试numpy-ml 为平滑模型提供了严谨的数值验证。numpy_ml/tests/test_ngram.py定义了以 NLTK 为基准的黄金实现MLEGold使用nltk.lm.MLE实现未平滑最大似然模型AdditiveGold使用nltk.lm.Lidstone(ordern, gammaK)实现 Additive 平滑。test_mle与test_additive两个测试测试源码的做法是用random_paragraph生成 1000 词随机段落写入临时文件分别用 numpy-ml 实现与 NLTK 黄金实现训练然后逐条断言两者 N-gram 计数完全一致并用np.testing.assert_allclose验证对数概率与 NLTK 结果换算到自然对数底误差在浮点精度内。测试随机化地取N ∈ [2, 5)、K取随机浮点数覆盖不同参数组合。这份测试直接证明了AdditiveNGram._log_ngram_prob公式与业界标准实现的一致性也让_log_ngram_prob中K * n_tokens的分母归一化设计有了可验证的落点。七、可视化对比三种平滑策略的效果差异仓库的绘图脚本 numpy_ml/plots/ngram_plots.py 提供了两种直观的可视化plot_gt_freqs(fp)脚本以对数-对数坐标绘制词频排名分布rank-probability 曲线叠加 MLE、simple Good-Turing、Laplace 三种估计。曲线整体越靠上、越平滑说明低频词的估计越合理——这正是numpy_ml/ngram/img/rank_probs.png展示的内容compare_probs(fp, N)脚本固定语料将K从 0 扫到 10观察 Additive 平滑对已见 N-gram如(bol, the)与未见 N-gram如(bol, asdf)对数概率的影响输出numpy_ml/ngram/img/add_smooth.png随着 K 增大已见 N-gram 的概率被稀释、未见 N-gram 的概率上升。结合第一节的架构分析可以总结出选型建议数据充足、追求最大似然时用MLENGram需要快速给零概率兜底时用AdditiveNGramK1 即 LaplaceK0.5 即 ELE对概率质量分配精度要求高、且语料规模足够支撑 count-of-counts 统计时优先选择GoodTuringNGram。结语N-gram 平滑是统计语言建模中小处见真章的经典问题。numpy-ml 用一个抽象基类NGramBase加三个具体子类把 Laplace、Additive/Lidstone 与 Good-Turing 三种平滑方案的数学公式收敛为各自_log_ngram_prob中短短几行 NumPy 代码并通过与 NLTK 的对照测试保证了数值正确性。无论你是想深入理解平滑公式的推导还是需要一个可读、可调试、可二次开发的纯 NumPy 语言模型实现都可以从 numpy_ml/ngram/ngram.py 与 numpy_ml/tests/test_ngram.py 入手配合本文的公式与 API 说明快速上手。赞分享机器学习人工智能【免费下载链接】numpy-mlMachine learning, in numpy项目地址https://gitcode.com/gh_mirrors/nu/numpy-ml点击查看免费下载相关推荐numpy-ml 中的 MLENGram无平滑 N-gram 语言模型原理、源码与实战指南numpy ml 中的 MLENGram无平滑 N gram 语言模型原理、源码与实战指南 本文基于 numpy ml 仓库的 ngram 模块文档 doc机器学习人工智能3步终极指南AdGuard浏览器扩展如何彻底改变你的上网体验3步终极指南AdGuard浏览器扩展如何彻底改变你的上网体验 AdGuard浏览器扩展是一款完全免费且开源的广告拦截工具它不仅能屏蔽烦人的广告更能全方位保前端网络安全基于 NumPy 实现隐马尔可夫模型numpy-ml MultinomialHMM 原理、推理与 Baum-Welch 训练实战指南基于 NumPy 实现隐马尔可夫模型numpy ml MultinomialHMM 原理、推理与 Baum Welch 训练实战指南 隐马尔可夫模型Hidd机器学习人工智能上一篇Sinatra请求验证确保API输入数据安全下一篇DeepSpec完全指南如何训练与评估高效推测解码算法创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。