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