【简介】
朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。最为广泛的两种分类模型是决策树模型(Decision Tree Model)和朴素贝叶斯模型(Naive Bayesian Model,NBM)。和决策树模型相比,朴素贝叶斯分类器(Naive Bayes Classifier,或 NBC)发源于古典数学理论,有着坚实的数学基础,以及稳定的分类效率。同时,NBC模型所需估计的参数很少,对缺失数据不太敏感,算法也比较简单。理论上,NBC模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为NBC模型假设属性之间相互独立,这个假设在实际应用中往往是不成立的,这给NBC模型的正确分类带来了一定影响(来自百度百科)。
【概念】
朴素贝叶斯公式:P( Category | Document) = P ( Document | Category ) * P( Category) / P(Document)
假设a1,a2,a3..........an互斥且构成一个完全事件,已知它们的概率P(ai),i=1,2,…,n,现观察到某事件A与a1,a2,a3..........an相伴随机出现,且已知条件概率P(A/ai),求P(ai/A)。即:已知某条件概率P(A|B),其交换事件P(B|A) = P(A|B)P(B)/P(A)
【注:P(A|B)表示事件B已经发生的前提下,事件A发生的概率,叫做事件B发生下事件A的条件概率。其基本求解公式为:P(A|B)=P(AB)/P(B)】
对于给出的待分类项,求解在此项出现的条件下各个类别出现的概率,哪个最大,就认为此待分类项属于哪个类别。所以程序里主要的工作就是计算出各个条件概率。
【阶段】
整个朴素贝叶斯分类分为三个阶段:
①准备工作阶段,这个阶段的任务是为朴素贝叶斯分类做必要的准备,主要工作是根据具体情况确定特征属性,并对每个特征属性进行适当划分,然后由人工对一部分待分类项进行分类,形成训练样本集合。这一阶段的输入是所有待分类数据,输出是特征属性和训练样本。这一阶段是整个朴素贝叶斯分类中唯一需要人工完成的阶段,其质量对整个过程将有重要影响,分类器的质量很大程度上由特征属性、特征属性划分及训练样本质量决定。
②分类器训练阶段,这个阶段的任务就是生成分类器,主要工作是计算每个类别在训练样本中的出现频率及每个特征属性划分对每个类别的条件概率估计,并将结果记录。其输入是特征属性和训练样本,输出是分类器。这一阶段是机械性阶段,根据前面讨论的公式可以由程序自动计算完成。
③应用阶段。这个阶段的任务是使用分类器对待分类项进行分类,其输入是分类器和待分类项,输出是待分类项与类别的映射关系。这一阶段也是机械性阶段,由程序完成。
①准备工作阶段,这个阶段的任务是为朴素贝叶斯分类做必要的准备,主要工作是根据具体情况确定特征属性,并对每个特征属性进行适当划分,然后由人工对一部分待分类项进行分类,形成训练样本集合。这一阶段的输入是所有待分类数据,输出是特征属性和训练样本。这一阶段是整个朴素贝叶斯分类中唯一需要人工完成的阶段,其质量对整个过程将有重要影响,分类器的质量很大程度上由特征属性、特征属性划分及训练样本质量决定。
②分类器训练阶段,这个阶段的任务就是生成分类器,主要工作是计算每个类别在训练样本中的出现频率及每个特征属性划分对每个类别的条件概率估计,并将结果记录。其输入是特征属性和训练样本,输出是分类器。这一阶段是机械性阶段,根据前面讨论的公式可以由程序自动计算完成。
③应用阶段。这个阶段的任务是使用分类器对待分类项进行分类,其输入是分类器和待分类项,输出是待分类项与类别的映射关系。这一阶段也是机械性阶段,由程序完成。
【代码】
# coding=utf-8
from numpy import *
# 初始化数据
# DataList 多条样例数据
# DataClass 数据对应的分类
def InitData():
DataList = [['data8'],
['data1', 'data2', 'data3', 'data4'],
['data1', 'data2', 'data5', 'data6'],
['data1', 'data2', 'data4', 'data6'],
['data8', 'data9'],
['data7', 'data8'],
['data1', 'data2'],
['data-invalid']]
DataClass = [1, 1, 2, 1, 2, 1, 2, 0]
return DataList, DataClass
# 去除重复数据
# UniqueSet 无重复的数据集
# 计算出数据DataSet中所有的数据种类
def UniqueSet(DataSet):
UniqueSet = set([])
for i in DataSet:
UniqueSet = UniqueSet | set(i) # set并
return list(UniqueSet)
# 数据状态压缩
# InputData 输入数据
# DataSet 数据集
# ModelType 模型类别 1:只考虑存不存在 2:考虑出现次数……
# CountArr 数据状态数组
def GetCountArr(InputData, DataSet, ModelType):
#创建DataSet长度的0数组
CountArr = [0] * len(DataSet)
#遍历数组
for i in InputData:
if i in DataSet:#判断元素是否存在于DataSet数组中
index=DataSet.index(i);#存在则获取元素在DataSet数组中的索引
#对CountArr根据ModelType赋值
if ModelType == 1:
CountArr[index] = 1
else:
CountArr[index] += 1
else:
print(i, ' is Invalid data')
return array(CountArr)
# 朴素贝叶斯分类器
# CountArrList 数据状态集
# DataClass 数据类别
# p1 p1概率自然对数
# p2 p2概率自然对数
# p1_ratio 数据集p1占比
# p2_ratio 数据集p2占比
# p1Num 数据集影响p1的数量
# p2Num 数据集影响p2的数量
def NBM_Classifier(CountArrList, DataClass):
ListLen = len(CountArrList)#获取数组行数
WordsLen = len(CountArrList[0])#获取数据列数
p1_ratio = (sum(DataClass == 1)) / float(ListLen)#判断类别为1的类型占行数的比例
p2_ratio = (sum(DataClass == 2)) / float(ListLen)#判断类别为2的类型占行数的比例
# 某分类下某词项出现频次为0时,其概率也是0,
# 因此在计算p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)会因为其中某个的概率为0而全部是0。
# 为了避免这样的情况发生,我们将所有词项出现的频次都初始化为1,某类所有词项数量初始化为2。
p1Num = ones(WordsLen)
p2Num = ones(WordsLen)
p1Denom = 2.0
p2Denom = 2.0
#逐行遍历数据
for i in range(ListLen):
#判断行数据属于的类型
if DataClass[i] == 1:
#如果属于该类,将数据叠加到p1Num中
p1Num += CountArrList[i]
p1Denom += sum(CountArrList[i])#求数据的和,添加到p1Denom中
elif DataClass[i] == 2:
p2Num += CountArrList[i]
p2Denom += sum(CountArrList[i])
# 由于p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)中每个因子都很小
# 所有因子相乘,特别是因子数量多的时候,会导致结果溢出,从而得到错误的数据
# 为了避免溢出问题的发生,使用求自然对数的方法
# 自然对数和原本的数值同增同减,不会有任何损失,因此不会影响求得的概率结果。
#相当于求某一类数据的数据平均分布情况
print(p1Num / p1Denom)#数组每个元素除以p1Denom总和的数
print(p2Num / p2Denom)#数组每个元素除以p1Denom总和的数
p1 = log(p1Num / p1Denom)
p2 = log(p2Num / p2Denom)
return p1, p2, p1_ratio, p2_ratio, p1Num - 1, p2Num - 1
# 获取数据类别
# CountArr 数据状态数组
# p1 p1概率自然对数
# p2 p2概率自然对数
# p1_ratio 数据集p1占比
# p2_ratio 数据集p2占比
# p1Num 数据集影响p1的数量
# p2Num 数据集影响p2的数量
def GetDataClass(CountArr, p1, p2, p1_ratio, p2_ratio, p1Num, p2Num):
# 无效数据:该数据没有影响过p1和p2
if sum(CountArr * p1Num) == 0 and sum(CountArr * p2Num) == 0:
return -1
# 数学公式:ln(a*b)=ln(a) +ln(b)
# 求实际数据在没类数据中的得分情况,取得分情况最高的情况
is_p1 = sum(CountArr * p1) + log(p1_ratio)
is_p2 = sum(CountArr * p2) + log(p2_ratio)
if is_p1 > is_p2:
return 1
else:
return 2
def Test():
DataList, DataClass = InitData()
UniqueDataList = UniqueSet(DataList)
ModelType = 1
CountArrList = []
for InputData in DataList:
CountArrList.append(GetCountArr(InputData, UniqueDataList, ModelType))
p1, p2, p1_ratio, p2_ratio, p1Num, p2Num = NBM_Classifier(array(CountArrList), array(DataClass))
TestData = [['data-invalid', 'data0'],
['data1', 'data2', 'data3', 'data5'],
['data4', 'data6'],
['data8'],
['data7', 'data8', 'data0']]
for InputData in TestData:
CountArr = GetCountArr(InputData, UniqueDataList, ModelType)
print(InputData, ' is class ', GetDataClass(CountArr, p1, p2, p1_ratio, p2_ratio, p1Num, p2Num))
Test()
【参考文献】
https://blog.csdn.net/sm9sun/article/details/78490550
http://blog.csdn.net/moxigandashu/article/details/71480251?locationNum=16&fps=1
https://www.cnblogs.com/leoo2sk/archive/2010/09/17/naive-bayesian-classifier.html
https://www.cnblogs.com/Dr-XLJ/p/5460625.html