朴素贝叶斯法
朴素贝叶斯法是基于贝叶斯定理和特征条件独立假设分类方法。对于给定训练集,首先基于特征条件独立性的假设,学习输入/输出联合概率(计算出先验概率和条件概率,然后求出联合概率)。然后基于此模型,给定输入x,利用贝叶斯概率定理求出最大的后验概率作为输出y。朴素贝叶斯法实现简单,学习和预测效率都很高,是一种常用的分类方法。
1、朴素贝叶斯法的学习与分类
1.1、基本方法
设输入空间X∈Rn为n维向量的集合,输出空间为类标记集合Y={c_1,c_2,⋯c_K},输入特征向量x∈X,输出为类标记y∈Y,X是定义为输入空间的随机变量,Y是输出空间的随机变量,P(X,Y)是联合概率分布,训练数据集:
由独立同分布产生。
朴素贝叶斯法是通过训练集学习联合概率分布P(X,Y),具体的则是学习先验概率分布和条件概率分布。
先验概率分布:
条件概率分布:
于是学习到联合概率P(X,Y)。
朴素贝叶斯法对条件概率分布进行了独立性条件假设。即:
条件独立性的假设等于说用于分类的特征在类确定的条件下都是独立条件,这一假设使得朴素贝叶斯法变得简单,但有时会牺牲一定的分类准确率。
朴素贝叶斯法进行分类时,对给定输入x,通过学习到的模型计算后验概率P( Y=c_k | X=x),将后验概率最大的类作为x的类输出。后验概率根据贝叶斯定理进行计算:
这是朴素贝叶斯分类器的基本公式,朴素贝叶斯分类器可以表示为:
后面的推断是由于所有的c_k都是相同的,分母是确定的一个定值,因此只需要分子最大化。
1.2、后验概率最大的含义
朴素贝叶斯法是将实例分到后验概率最大类中,这等于期望风险最小化,假设选择0-1损失函数。
其中f(x)是决策分类函数。期望风险函数为:
为了是期望风险最小:
这样一来就可以知道期望风险最小化准则就是后验概率最大化准则。
2、朴素贝叶斯法的参数估计
2.1、极大似然估计
在朴素贝叶斯法,学习意味着估计先验概率P(Y=c_k )和条件概率P(X=x| Y=c_k )。也可以用极大似然估计法估计相应的概率,先验概率P(Y=c_k )的极大似然估计是:
设第j个特征x^j可能的取值的{a_j1,a_j1,⋯,a_(jS_j )}。条件概率的极大似然估计为:
其中x_i^j表示第i个样本第j个特征。a_jl是表示第j个特征取第l的值。I为指示函数。
2.2、学习与分类算法
2.3、贝叶斯估计
用极大似然估计可能会出现所要估计概率值为0的情况;这会影响到后验概率的计算。使分类产生偏差,解决这一个问题的办法是使用贝叶斯估计。具体是在条件概率的分子分母分加上一个数。如下:
其中λ≥0。等价于在随机变量各个取值的频数上赋予一个正数λ>0;λ=0是极大似然估计。常取λ=1,称为拉普拉斯平滑。显然对于任何l=1,2,⋯,S_j;k=1,2,⋯,K有:
同样先验概率有:
最后附上代码:
from math import log, exp
class Laplace(object):
def __init__(self):
self.d = {}
self.total = 0.0
self.none = 1
def exists(self, key):
return key in self.d
def getsum(self):
return self.total
def get(self, key):
if not self.exists(key):
return False, self.none
return True, self.d[key]
def getprob(self, key):
return float(self.get(key)[1]) / self.total
def samples(self):
return self.d.keys()
def add(self, key, value):
self.total += value
if not self.exists(key):
self.d[key] = 1
self.total += 1
self.d[key] += value
class Bayes(object):
def __init__(self):
# [label, Probability] map
self.d = {}
self.total = 0
# train data set
def train(self, data):
for d in data:
c = d[1] # Probability
if c not in self.d:
self.d[c] = Laplace() # Laplacian smoothing
for w in d[0]: # label
self.d[c].add(w, 1)
self.total = sum(map(lambda x: self.d[x].getsum(), self.d.keys()))
def classify(self, x):
temp = {}
for c in self.d:
temp[c] = log(self.d[c].getsum()) - log(self.total)
for w in x:
temp[c] += log(self.d[c].getprob(w))
ret, prob = 0, 0
for c in self.d:
now = 0
try:
for otherc in self.d:
now += exp(temp[otherc] - temp[c])
now = 1 / now
except OverflowError:
now = 0
if now > prob:
ret, prob = c, now
return (ret, prob)