当前位置: 首页 > ds >正文

N-gram语言模型原理与实战教程

在自然语言处理(NLP)领域,语言模型(Language Model)是评估一句话是否**“通顺”**的基础工具。尤其在早期 NLP 中,N-gram 是非常经典且高效的一类统计语言模型。

什么是 N-gram?

N-gram 是自然语言处理中,将文本按连续的 N 个词(或字符)划分的技术。

  • N=1:Unigram,单个词
  • N=2:Bigram,两个连续词 - 一阶马尔科夫
  • N=3:Trigram,三个连续词 - 二阶马尔科夫

例如句子:“我 爱 自然 语言”,它的 Bigram 是:“我 爱”,“爱 自然”,“自然 语言”。

马尔科夫假设(Markov Assumption)

在自然语言处理中,我们经常需要预测一句话中下一个单词的概率。而为了简化计算复杂度,马尔科夫假设(Markov Assumption) 就应运而生,成为 N-gram 语言模型等传统 NLP 方法的数学基础。

马尔科夫假设指的是:当前状态的概率,只依赖于有限个前置状态,而与更早的历史无关。
简单说,马尔科夫假设就是“当前只看前面有限几个词,不用全历史”,方便快速做语言预测。

数学定义

一句话: P(w_1, w_2, w_3, \ldots, w_n)

马尔科夫假设简化成:

  • 一阶马尔科夫(Bigram): P(w_n | w_1, w_2, \ldots, w_{n-1}) \approx P(w_n | w_{n-1})
  • 二阶马尔科夫(Trigram): P(w_n | w_1, w_2, \ldots, w_{n-1}) \approx P(w_n | w_{n-2}, w_{n-1})

举例说明

原句我 爱 自然 语言 处理
如果用 Bigram 模型计算:

P(我, 爱, 自然, 语言, 处理)
= P(我) \times  P(爱|我) \times  P(自然|爱) \times  P(语言|自然) \times  P(处理|语言)

什么是 N-gram 语言模型?

N-gram 是一种基于统计的方法,通过计算连续 N 个单词组成的子序列出现的概率,来预测下一个单词或评估整个句子。

  • Unigram(一元模型):只看当前词
  • Bigram(二元模型):看当前词和前一个词
  • Trigram(三元模型):看当前词和前两个词

N-gram 语言模型应用场景

场景用途说明
拼写纠错判断词对合法性,检测异常搭配
文本生成基于已有语料预测下一个单词,自动续写句子
语言模型评分计算一句话的概率,判断其通顺程度
分词与文本纠错在中文 NLP 分词、句子切分中辅助作用

Python 实战:N-gram 模型实现

环境准备

import nltk
from nltk.util import ngrams
from nltk.tokenize import word_tokenize
from nltk import FreqDist
from collections import Counter
import randomnltk.download('punkt')

训练预料

text = "我 爱 自然 语言 处理 和 机器 学习  我 爱 美女 也 爱 美食"
tokens = word_tokenize(text)
bigrams = list(ngrams(tokens, 2))
print(f"bigrams:{bigrams}")
fdist = FreqDist(bigrams)
fdist

输出

bigrams:[('我', '爱'), ('爱', '自然'), ('自然', '语言'), ('语言', '处理'), ('处理', '和'), ('和', '机器'), ('机器', '学习'), ('学习', '我'), ('我', '爱'), ('爱', '美女'), ('美女', '也'), ('也', '爱'), ('爱', '美食')]
FreqDist({('我', '爱'): 2, ('爱', '自然'): 1, ('自然', '语言'): 1, ('语言', '处理'): 1, ('处理', '和'): 1, ('和', '机器'): 1, ('机器', '学习'): 1, ('学习', '我'): 1, ('爱', '美女'): 1, ('美女', '也'): 1, ...})

1.拼写纠错案例

# 判断词对是否合理
def is_valid_bigram(w1, w2):return fdist[(w1, w2)] > 0# 📑 Test Case
test_sentences = ["我 爱 自然 语言","自然 学习 机器"
]for sentence in test_sentences:print(f"\n检测句子: {sentence}")test_tokens = word_tokenize(sentence)test_bigrams = list(ngrams(test_tokens, 2))for bigram in test_bigrams:if is_valid_bigram(bigram[0], bigram[1]):print(f"✔️ {bigram} 合法")else:print(f"❌ {bigram} 可疑")

输出

检测句子: 我 爱 自然 语言
✔️ ('我', '爱') 合法
✔️ ('爱', '自然') 合法
✔️ ('自然', '语言') 合法检测句子: 自然 学习 机器
❌ ('自然', '学习') 可疑
❌ ('学习', '机器') 可疑

2.文本生成案例

构建 Bigram 词典

# 构建 Bigram 词典
model = {}
for w1, w2 in bigrams:if w1 in model:model[w1].append(w2)else:model[w1] = [w2]
model

输出

{'我': ['爱', '爱'],'爱': ['自然', '美女', '美食'],'自然': ['语言'],'语言': ['处理'],'处理': ['和'],'和': ['机器'],'机器': ['学习'],'学习': ['我'],'美女': ['也'],'也': ['爱']}

生成句子

# 生成句子(长度为6个词)
def generate_sentence(start_word, length=6):result = [start_word]for _ in range(length - 1):next_words = model.get(result[-1])if not next_words:breaknext_word = random.choice(next_words)result.append(next_word)return ' '.join(result)# 📑 Test Case
print("\n📌 文本生成示例:")
print(generate_sentence("我"))
print(generate_sentence("语言"))

输出

📌 文本生成示例:
我 爱 自然 语言 处理 和
语言 处理 和 机器 学习 我

3.语言模型评分案例

w2

from collections import Counter
# Bigram + Unigram 频率表
bigram_counts = Counter(bigrams)
bigram_counts

输出

Counter({('我', '爱'): 2,('爱', '自然'): 1,('自然', '语言'): 1,('语言', '处理'): 1,('处理', '和'): 1,('和', '机器'): 1,('机器', '学习'): 1,('学习', '我'): 1,('爱', '美女'): 1,('美女', '也'): 1,('也', '爱'): 1,('爱', '美食'): 1})

w1

unigram_counts = Counter(tokens) # 单个词,
unigram_counts

输出

Counter({'爱': 3,'我': 2,'自然': 1,'语言': 1,'处理': 1,'和': 1,'机器': 1,'学习': 1,'美女': 1,'也': 1,'美食': 1})

计算句子概率

# 计算 P(w2|w1)
def bigram_prob(w1, w2):return bigram_counts[(w1, w2)] / unigram_counts[w1] if unigram_counts[w1] > 0 else 0# 计算句子概率
def sentence_prob(sentence):tokens = word_tokenize(sentence)sentence_bigrams = list(ngrams(tokens, 2))prob = 1.0for w1, w2 in sentence_bigrams:p = bigram_prob(w1, w2)if p == 0:prob *= 1e-6  # 平滑处理,表示一个接近0的值else:prob *= preturn prob# 📑 Test Case
test_sentences = ["我 爱 自然 语言","自然 学习 机器","机器 学习"
]print("\n📌 句子概率评分:")
for sentence in test_sentences:print(f"'{sentence}' 概率: {sentence_prob(sentence)}")

输出

📌 句子概率评分:
'我 爱 自然 语言' 概率: 0.3333333333333333
'自然 学习 机器' 概率: 1e-12
'机器 学习' 概率: 1.0
http://www.xdnf.cn/news/8317.html

相关文章:

  • sqli-labs第二十一/二十二关——POST-base64
  • STL 转 STP 深度技术指南:从 3D 打印模型到工程标准的跨领域转换全解析(附迪威模型在线方案)
  • 亚马逊选品可以从以下几个方面着手
  • 浙江大学python程序设计(陈春晖、翁恺、季江民)习题答案-第十章
  • 各种标准的简称和字母标识
  • 01-jenkins学习之旅-window-下载-安装-安装后设置向导
  • Android 串口-usb-serial-for-android
  • Spring Boot——自动配置
  • 如何给文件夹添加编号?批量给文件夹添加数字、字母、日期编号
  • 前端判空:与后端 “千层套路” 的斗智斗勇
  • highCharts生成3D饼图
  • 若依Ruoyi富文本编辑器Quill粘贴图片改成文件上传(不使用base64)
  • 【C/C++】深入解析Linux下C/C++内存管理全攻略(纲要)
  • 从0到1玩转TypeScript:开启类型世界的奇妙冒险
  • 基于 AMDXCVU13P FPGA 的 4 路 100G 光纤 PCIe 低时延高性能计算加速卡
  • MCP Server StreamableHTTP 开发学习文档
  • RT-Thread源码阅读(2)——任务启动与调度
  • ArkTs中的尾随闭包
  • 如何重新设置网络ip地址?全面解析多种方法
  • 第八天 搭建车辆状态监控平台(Docker+Kubernetes) OTA升级服务开发(差分升级、回滚机制)
  • eNSP防火墙实现GRE over IPSec
  • 文件操作和IO-3 文件内容的读写
  • 【Java高阶面经:数据库篇】16、分库分表主键:如何设计一个高性能唯一ID
  • transformer网络
  • 云曦25年春季期中考核复现
  • 【会议推荐|权威出版】2025年电力工程与电气技术国际会议(PEET 2025)
  • Python 训练 day31
  • ssh登录设备总提示密码错误解决方法
  • 使用 Navicat 17 for PostgreSQL 时,请问哪个版本支持 PostgreSQL 的 20150623 版本?还是每个版本都支持?
  • Skia如何在窗口上绘图