贝叶斯简介:
贝叶斯(约1701-1761) Thomas Bayes,英国数学家。贝叶斯方法源于他生前为解决一个“逆概”问题写的一篇文章,生不逢时,死后它的作品才被世人认可。
贝叶斯要解决的问题:
正向概率:假设袋子里面有N个白球,M个黑球,你伸手进去摸一把,摸出黑球的概率是多大
逆向概率:如果我们事先并不知道袋子里面黑白球的比例,而是闭着眼睛摸出一个(或好几个)球,观察这些取出来的球的颜色之后,那么我们
可以就此对袋子里面的黑白球的比例作出什么样的推测。
Why贝叶斯?
现实世界本身就是不确定的,人类的观察能力是有局限性的我们日常所观察到的只是事物表面上的结果,因此我们需要
提供一个猜测。
贝叶斯公式推导
贝叶斯公式:
贝叶斯公式是条件概率 + 全概率 + 乘法公式的组合 。
条件概率
设A,B两个事件,且P(B)>0,则在B发生的条件下,A发生的概率为: P(A|B) = P(AB) / P(B)
注:A,B两个事件不一定是独立事件。若为独立事件则:P(A|B) = P(A) 即B的发生不会影响A的发生。所以
P(A|B) = P(AB) / P(B) = P(A) ==> P(AB) = P(A) P(B)。
案例:使用贝叶斯公式来进行单词拼写纠正
问题:用户输入词汇w,这个词汇w可能是是一个错误单词,系统需要猜测用户真正想要输入的词汇是什么,记猜测词汇为c。
答:根据问题就是求 P(c|w) 的最大值,根据贝叶斯公式:P(c|w) = P(w|c)P(c) / P(w) ,因为对于不同的具体猜测c1,c2,c3...,P(w)都是一样的,所在在比较P(c1|w)和P(c2|w)时可以忽略P(w)这个参数,所以P(c|w) = P(w|c)P(c) / P(w) ∝ P(w|c)P(c) ,这样就等价于求P(w|c)P(c)最大值。
- P(c), 在词库中出现 c 的概率,为先验概率
- P(w|c), 在用户输入词库中单词 c 的情况下敲成 w 的概率,即猜测生成我们观测数据的可能性的大小。
要计算P(w|c),此时需要用到编辑距离的概念,编辑距离0表示不作变换,编辑距离1变换表示对单词做一个字母的增删改查,编辑距离2变换表示对单词做两个字母的增删改查,以此类推。因为要计算词库中单词c的情况下,则对词库中每个单词做编辑距离0变换, 若变换后假设c5与用户的输入单词w一致,则保留c5至eidt_0_set = {c5};再对词库中每个单词c做编辑距离1变换,若变换后与用户的输入单词w一致,则保留词库中单词c至集合 edit1_set = {c3,c5...} ,认为edit1_set集合中词汇P(w|c3) = P(w|c5) = .... 都是一样的;以此类推,再对用户做编辑距离2计算。在实际代码中,可以将用户输入单词w做编辑距离变换,查看查看是否在词库中存
我们预先认为P(w|c, edit_0) >> P(w|c, edit_1) >> P(w|c, edit_2)...,则不论P(c)概率为多少,P(w|c, edit_0)P(c) >> P(w|c, edit_1)P(c) >> P(w|c, edit_2)P(c) , 其中,P(w|c, edit_0)表示词汇做编辑距离0的条件下,P(w|c)的概率)。所以当edit_1_set不为空,认为edit_1_set中单词即为用户想输入的词汇,如果所以当edit_0_set为空,再判断edit_1_set是否为空,若不为空,则计算edit_1_set中每个词汇的先验概率P(ci),取出P(ci)值最大对应的那个词汇ci 即为用户想输入的词汇,如果edit_1_set为空再计算edit2情形,依次类推,本例子为了简单,只计算到edit2,如果edit_0,edit_1,edit_2都为空,则认为不知道用户输入啥词汇,返回原值。
Python代码
import re, collections
# 把语料中的单词全部抽取出来, 转成小写, 并且去除单词中间的特殊符号
def words(text): return re.findall('[a-z]+', text.lower())
def train(features):
model = collections.defaultdict(lambda: 1)
for f in features:
model[f] += 1
return model
# 统计每个单词出现的频率,字典形式
NWORDS = train(words(open('big.txt').read()))
NWORDS
alphabet = 'abcdefghijklmnopqrstuvwxyz'
def edits1(word):
n = len(word)
return set([word[0:i]+word[i+1:] for i in range(n)] + # deletion
[word[0:i]+word[i+1]+word[i]+word[i+2:] for i in range(n-1)] + # transposition
[word[0:i]+c+word[i+1:] for i in range(n) for c in alphabet] + # alteration
[word[0:i]+c+word[i:] for i in range(n+1) for c in alphabet]) # insertion
def known_edits2(word):
return set(e2 for e1 in edits1(word) for e2 in edits1(e1) if e2 in NWORDS)
def known(words):
# 判断用户输入单词是否在词库里
return set(w for w in words if w in NWORDS)
def correct(word):
# known([word]) = edit0_set ; known(edits1(word)) = edit1_set;known_edits2(word) = edit2_set
candidates = known([word]) or known(edits1(word)) or known_edits2(word) or [word]
return max(candidates, key=lambda w: NWORDS[w])
correct('koot')
'foot'