共计 3110 个字符,预计需要花费 8 分钟才能阅读完成。
朴素贝叶斯概念
在上一篇文章中讲到贝叶斯基本概念问题以及贝叶斯分类器的最优化问题,最优化的最终是要最大化后验概率估计,但是后验概率的计算涉及到联合概率分布,然而计算联合概率分布需要大量的样本,在实际的操作过程中根本无法达到,为了避开这个问题,朴素贝叶斯假设给定的分类对应的样本属性是相互独立的,从另外一个角度来说就是一个样本中包含的各种属性对其分类的结果影响是独立的。
举个栗子,西瓜的属性有颜色,根蒂,纹理,敲声等多种属性,根据朴素贝叶斯的定义则一个西瓜样本的颜色属性对当前样本的分类结果影响与根蒂对分类结果的影响是独立的。
针对上述情况后验概率估计就变得简单了
朴素贝叶斯分类是一种十分简单的分类算法,叫它朴素贝叶斯分类是因为这种方法的思想真的很朴素,朴素贝叶斯的思想基础是这样的:对于给出的待分类项,求解在此项出现的条件下各个类别出现的概率,哪个最大,就认为此待分类项属于哪个类别。通俗来说,就好比这么个道理,你在街上看到一个黑人,我问你你猜这哥们哪里来的,你十有八九猜非洲。为什么呢?因为黑人中非洲人的比率最高,当然人家也可能是美洲人或亚洲人,但在没有其它可用信息下,我们会选择条件概率最大的类别,这就是朴素贝叶斯的思想基础。
朴素贝叶斯分类的正式定义如下:
1、设为一个待分类项,而每个a为x的一个特征属性。
2、有类别集合。
3、计算。
4、如果,则。
那么现在的关键就是如何计算第3步中的各个条件概率。我们可以这么做:
1、找到一个已知分类的待分类项集合,这个集合叫做训练样本集。
2、统计得到在各类别下各个特征属性的条件概率估计。即。
3、如果各个特征属性是条件独立的,则根据贝叶斯定理有如下推导:
因为分母对于所有类别为常数,因为我们只要将分子最大化皆可。又因为各特征属性是条件独立的,所以有:
拉普拉斯校准
这一节讨论P(a|y)的估计。
由上文看出,计算各个划分的条件概率P(a|y)是朴素贝叶斯分类的关键性步骤,当特征属性为离散值时,只要很方便的统计训练样本中各个划分在每个类别中出现的频率即可用来估计P(a|y),下面重点讨论特征属性是连续值的情况。
当特征属性为连续值时,通常假定其值服从高斯分布(也称正态分布)。即:
而
因此只要计算出训练样本中各个类别中此特征项划分的各均值和标准差,代入上述公式即可得到需要的估计值。均值与标准差的计算在此不再赘述。
另一个需要讨论的问题就是当P(a|y)=0怎么办,当某个类别下某个特征项划分没有出现时,就是产生这种现象,这会令分类器质量大大降低。为了解决这个问题,我们引入Laplace校准,它的思想非常简单,就是对没类别下所有划分的计数加1,这样如果训练样本集数量充分大时,并不会对结果产生影响,并且解决了上述频率为0的尴尬局面。
代码实践
# -*- coding: utf-8 -*-
import csv
import numpy as np
from math import sqrt
attr_num=[3,3,3,3,3,2]
def loadCsv(filename):
lines = csv.reader(open(filename, "rb"))
dataset = list(lines)
for i in range(1,len(dataset)):
dataset[i] = [float(x) for x in dataset[i] ]
result=np.array(dataset[1:])
return result[:,1:]
def pre_problity(datasets):
pos_prob=1.0*(np.sum(datasets[:,-1]==1.0)+1)/(np.shape(datasets)[0]+2)
neg_prob=1.0*(np.sum(datasets[:,-1]==0.0)+1)/(np.shape(datasets)[0]+2)
return [pos_prob,neg_prob]
def cond_attr_problity(datasets,testdata):
cond_result=np.zeros([np.shape(datasets)[1]-1,2])
pos_data=datasets[datasets[:,-1]==1.0,:]
neg_data=datasets[datasets[:,-1]==0.0,:]
for i in range(len(attr_num)):
cond_result[i,0]=1.0*(np.sum(pos_data[:,i]==testdata[0,i])+1)/(np.sum(datasets[:,-1]==1.0)+attr_num[i])
cond_result[i,1]=1.0*(np.sum(neg_data[:,i]==testdata[0,i])+1)/(np.sum(datasets[:,-1]==0.0)+attr_num[i])
for j in range(6,8):
# mean,std computation
pos_mean=np.mean(datasets[(datasets[:,-1]==1.0),j])
pos_std=np.std(datasets[(datasets[:,-1]==1.0),j])
neg_mean=np.mean(datasets[(datasets[:,-1]==0.0),j])
neg_std=np.std(datasets[(datasets[:,-1]==0.0),j])
cond_result[j,0]=1.0/(sqrt(2*np.pi)*pos_std)*np.exp(-1*(testdata[0,j]-pos_mean)**2/(2*pos_std**2))
cond_result[j,1]=1.0/(sqrt(2*np.pi)*neg_std)*np.exp(-1*(testdata[0,j]-neg_mean)**2/(2*neg_std**2))
return cond_result
def classify_data(cond_result,pre_result):
pos_result=pre_result[0]
neg_result=pre_result[1]
for i in range(np.shape(cond_result)[0]):
pos_result*=cond_result[i,0]
neg_result*=cond_result[i,1]
if pos_result>neg_result:
print 'pos'
print pos_result
else:
print 'neg'
print neg_result
def main():
filename = 'watermelon3_0_En.csv'
dataset = loadCsv(filename)
testname = 'test.csv'
testdata = loadCsv(testname)
pre_result=pre_problity(dataset)
cond_result=cond_attr_problity(dataset,testdata)
classify_data(cond_result,pre_result)
main()
下面给出相应的数据文件下载
[dl href=’http://7xifjo.com1.z0.glb.clouddn.com/watermelon3_0_En.csv’]西瓜数据样本文件[/dl]
[dl href=’http://7xifjo.com1.z0.glb.clouddn.com/test.csv’]测试样本文件[/dl]