统计语言模型Python实现

原理简述

统计语言模型(Statistical Language Model),可用于计算一个句子的合理程度。
S S S 表示句子,由有序的 n n n 个词 w 1 , w 2 , w 3 , . . w n w_1,w_2,w_3,..w_n w1,w2,w3,..wn 组成,句子概率 P ( S ) P(S) P(S) 的计算公式如下:

N-gram

P ( S ) = P ( w 1 , w 2 , . . . w n ) = P ( w 1 ) P ( w 2 ∣ w 1 ) P ( w 3 ∣ w 1 , w 2 ) . . . P ( w n ∣ w 1 , w 2 , . . . w n − 1 ) P(S) =P(w_1,w_2,...w_n) =P(w_1)P(w_2|w_1)P(w_3|w_1,w_2)...P(w_n|w_1,w_2,...w_{n-1}) P(S)=P(w1,w2,...wn)=P(w1)P(w2w1)P(w3w1,w2)...P(wnw1,w2,...wn1)

unigram

P ( S ) = P ( w 1 ) P ( w 2 ) . . . P ( w n ) = ∏ i = 1 n P ( w i ) P(S)=P(w_1)P(w_2)...P(w_n)=\prod^n_{i=1}P(w_i) P(S)=P(w1)P(w2)...P(wn)=i=1nP(wi)
log ⁡ P ( S ) = ∑ i = 1 n log ⁡ P ( w i ) \log P(S) = \sum^n_{i=1} \log P(w_i) logP(S)=i=1nlogP(wi)

bigram

P ( S ) = P ( w 1 ) P ( w 2 ∣ w 1 ) P ( w 3 ∣ w 2 ) . . . P ( w n ∣ w n − 1 ) = P ( w 1 ) ∏ i = 2 n P ( w i ∣ w i − 1 ) P(S) =P(w_1)P(w_2|w_1)P(w_3|w_2)...P(w_n|w_{n-1}) =P(w_1)\prod^n_{i=2}P(w_i|w_{i-1}) P(S)=P(w1)P(w2w1)P(w3w2)...P(wnwn1)=P(w1)i=2nP(wiwi1)
log ⁡ P ( S ) = log ⁡ P ( w 1 ) + ∑ i = 2 n log ⁡ P ( w i ∣ w i − 1 ) \log P(S) = \log P(w_1) + \sum^n_{i=2} \log P(w_i|w_{i-1}) logP(S)=logP(w1)+i=2nlogP(wiwi1)

Add-k Smoothing

k=1;bigram;C表示count
P A d d − 1 ( w i ∣ w i − 1 ) = C ( w i − 1 , w i ) + 1 C ( w i − 1 ) + V P_{Add-1}(w_i|w_{i-1})=\frac{C(w_{i-1},w_i)+1}{C(w_{i-1})+V} PAdd1(wiwi1)=C(wi1)+VC(wi1,wi)+1
e.g.

我很帅
她很美
P ( 帅 ∣ 很 ) = 1 + 1 2 + 5 = 2 7 P(帅|很)=\frac{1+1}{2+5}=\frac{2}{7} P()=2+51+1=72
P ( 美 ∣ 很 ) = 1 + 1 2 + 5 = 2 7 P(美|很)=\frac{1+1}{2+5}=\frac{2}{7} P()=2+51+1=72
P ( 我 ∣ 很 ) = 0 + 1 2 + 5 = 1 7 P(我|很)=\frac{0+1}{2+5}=\frac{1}{7} P()=2+50+1=71
P ( 她 ∣ 很 ) = 0 + 1 2 + 5 = 1 7 P(她|很)=\frac{0+1}{2+5}=\frac{1}{7} P()=2+50+1=71
P ( 很 ∣ 很 ) = 0 + 1 2 + 5 = 1 7 P(很|很)=\frac{0+1}{2+5}=\frac{1}{7} P()=2+50+1=71
P 总 = 1 P_总=1 P=1

代码&步骤

from collections import Counter
import numpy as np


"""语料"""
corpus = '''她的菜很好 她的菜很香 她的他很好 他的菜很香 他的她很好
很香的菜 很好的她 很菜的他 她的好 菜的香 他的菜 她很好 他很菜 菜很好'''.split()


"""语料预处理"""
counter = Counter()  # 词频统计
for sentence in corpus:
    for word in sentence:
        counter[word] += 1
counter = counter.most_common()
lec = len(counter)
word2id = {counter[i][0]: i for i in range(lec)}
id2word = {i: w for w, i in word2id.items()}


"""N-gram建模训练"""
unigram = np.array([i[1] for i in counter]) / sum(i[1] for i in counter)

bigram = np.zeros((lec, lec)) + 1e-8
for sentence in corpus:
    sentence = [word2id[w] for w in sentence]
    for i in range(1, len(sentence)):
        bigram[[sentence[i - 1]], [sentence[i]]] += 1
for i in range(lec):
    bigram[i] /= bigram[i].sum()


"""句子概率"""
def prob(sentence):
    s = [word2id[w] for w in sentence]
    les = len(s)
    if les < 1:
        return 0
    p = unigram[s[0]]
    if les < 2:
        return p
    for i in range(1, les):
        p *= bigram[s[i - 1], s[i]]
    return p

print('很好的菜', prob('很好的菜'))
print('菜很好的', prob('菜很好的'))
print('菜好的很', prob('菜好的很'))


"""排列组合"""
def permutation_and_combination(ls_ori, ls_all=None):
    ls_all = ls_all or [[]]
    le = len(ls_ori)
    if le == 1:
        ls_all[-1].append(ls_ori[0])
        ls_all.append(ls_all[-1][: -2])
        return ls_all
    for i in range(le):
        ls, lsi = ls_ori[:i] + ls_ori[i + 1:], ls_ori[i]
        ls_all[-1].append(lsi)
        ls_all = permutation_and_combination(ls, ls_all)
    if ls_all[-1]:
        ls_all[-1].pop()
    else:
        ls_all.pop()
    return ls_all

print('123排列组合', permutation_and_combination([1, 2, 3]))


"""给定词组,返回最大概率组合的句子"""
def max_prob(words):
    pc = permutation_and_combination(words)  # 生成排列组合
    p, w = max((prob(s), s) for s in pc)
    return p, ''.join(w)

print(*max_prob(list('香很的菜')))
print(*max_prob(list('好很的他菜')))
print(*max_prob(list('好很的的她菜')))

1、工具导入

from collections import Counter
import numpy as np, pandas as pd
pdf = lambda data, index=None, columns=None: pd.DataFrame(data, index, columns)

pandas用于可视化(Jupyter下),亦可用matplotlib、seaborn等工具

2、语料预处理

corpus = '她很香 她很菜 她很好 他很菜 他很好 菜很好'.split()

counter = Counter()  # 词频统计
for sentence in corpus:
    for word in sentence:
        counter[word] += 1
counter = counter.most_common()
words = [wc[0] for wc in counter]  # 词库(用于可视化)
lec = len(counter)
word2id = {counter[i][0]: i for i in range(lec)}
id2word = {i: w for w, i in word2id.items()}

pdf(counter, None, ['word', 'freq'])

3、unigram

unigram = np.array([i[1] for i in counter]) / sum(i[1] for i in counter)
pdf(unigram.reshape(1, lec), ['概率'], words)

4、bigram

bigram = np.zeros((lec, lec)) + 1e-8  # 平滑

for sentence in corpus:
    sentence = [word2id[w] for w in sentence]
    for i in range(1, len(sentence)):
        bigram[[sentence[i - 1]], [sentence[i]]] += 1

# 频数
pd.DataFrame(bigram, words, words, int)

# 频数 --> 概率
for i in range(lec):
    bigram[i] /= bigram[i].sum()
pdf(bigram, words, words)

5、概率计算

def prob(sentence):
    s = [word2id[w] for w in sentence]
    les = len(s)
    if les < 1:
        return 0
    p = unigram[s[0]]
    if les < 2:
        return p
    for i in range(1, les):
        p *= bigram[s[i - 1], s[i]]
    return p

print(prob('菜很香'), 1 / 6 / 6)

p ( 菜 很 香 ) = P ( 菜 ) P ( 很 ∣ 菜 ) P ( 香 ∣ 很 ) = 3 18 ∗ 1 ∗ 1 6 p(菜很香)=P(菜)P(很|菜)P(香|很)= \frac{3}{18} * 1 * \frac{1}{6} p()=P()P()P()=183161

基于Bigram的文本生成

https://github.com/AryeYellow/NLP/blob/master/TextGeneration/tg_trigram_and_cnn.ipynb

from collections import Counter
from random import choice
from jieba import lcut

# 语料读取、分词
with open('corpus.txt', encoding='utf-8') as f:
    corpus = [lcut(line) for line in f.read().strip().split()]

# 词频统计
counter = Counter(word for words in corpus for word in words)

# N-gram建模训练
bigram = {w: Counter() for w in counter.keys()}
for words in corpus:
    for i in range(1, len(words)):
        bigram[words[i - 1]][words[i]] += 1
for k, v in bigram.items():
    total2 = sum(v.values())
    v = {w: c / total2 for w, c in v.items()}
    bigram[k] = v

# 文本生成
n = 5  # 开放度
while True:
    first = input('首字:').strip()
    if first not in counter:
        first = choice(list(counter))
    next_words = sorted(bigram[first], key=lambda w: bigram[first][w])[:n]
    next_word = choice(next_words) if next_words else ''
    sentence = first + next_word
    while bigram[next_word]:
        next_word = choice(sorted(bigram[next_word], key=lambda w: bigram[next_word][w])[:n])
        sentence += next_word
    print(sentence)

附录

encn
grammar语法
unique唯一的
binary二元的
permutation排列
combination组合

统计语言模型应用于词性标注Python算法实现

Python是数据科学和机器学习领域中非常流行的语言,其中有许多强大的库支持概率论和统计模型实现。其中两个核心库是NumPy和SciPy,它们提供了大量的数学函数和算法,而更高级的库如Pandas用于数据处理,matplotlib和seaborn则用于数据可视化。 在概率论方面,你可以使用: 1. `numpy.random`模块:提供了各种随机数生成器,如均匀分布、正态分布等。 2. `scipy.stats`模块:包含许多概率分布和统计测试函数,比如计算累积分布函数(CDF)、概率密度函数(PDF)或进行假设检验。 3. `statsmodels`库:提供更高级的统计模型,如线性回归、时间序列分析、以及各种假设检验。 在统计模型方面,有: 1. `sklearn`(scikit-learn):这是机器学习的基础库,包含了诸如线性回归、决策树、聚类算法、分类器等常用统计模型。 2. `pandas`的数据框结构非常适合数据探索和预处理,这对于构建统计模型至关重要。 3. `pyMC3`和`Stan`:用于构建和估计贝叶斯模型的库,支持概率编程。 4. `TensorFlow Probability`或`Edward`:如果你需要在深度学习背景下使用概率模型,这些库提供了概率图模型和自动概率编程功能。 如果你对某个特定的统计模型或概率方法感兴趣,例如贝叶斯网络、马尔可夫链蒙特卡洛(MCMC)或时间序列分析,请告诉我,我可以为你提供更详细的介绍和代码示例。另外,还有许多用于机器学习的高级库,如`Keras`和`TensorFlow`,它们也支持概率相关的组件。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小基基o_O

您的鼓励是我创作的巨大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值