[关闭]
@77qingliu 2018-04-24T01:15:39.000000Z 字数 5318 阅读 1763

朴素贝叶斯分类器

machine-learning python


概述

朴素贝叶斯(Naive Bayes)是基于贝叶斯公式与特征条件独立的建设,估计后验概率,根据后验概率进行分类的监督学习方法。对于给定的训练数据集,首先基于特征条件独立的假设学习输入/输出的联合概率分布;然后基于此模型,对给定的输入,利用贝叶斯公式求出后验概率最大的输出。

原理

贝叶斯定理


其中,是先验概率;是样本相对于类标记c的类条件概率;是用于归一化的证据因子。贝叶斯公式可以看作是根据后验证信息,对先验概率进行“校正”。对给定样本,证据因子与类标记无关,因此估计的问题转化为如何基于训练数据D来估计先验概率和条件概率。

朴素贝叶斯

类先验概率表达了样本占空间中各类样本所占的比例,根据大数定理,当训练集中包含充足的独立同分布样本时,可以通过各类样本的频率进行估计。这里其实是极大似然估计的思想。

对类条件概率来说,由于涉及关于的所有属性的联合概率,直接根据样本出现的频率进行估计将会出现严重困难。例如,假设样本中的个属性都是二值的,则样本空间中将有种可能的取值。很多样本取值在训练集中根本没有出现,直接用频率来估计是不可行的。为避开这个障碍,“朴素贝叶斯分类器”采用了“属性条件独立性假设”:对已知的类别,假设所有属性相互独立。换言之,假设每个属性独立地对分类结果产生影响。
基于条件独立性的假设,可重写为:


其中为属性数目,为在第个属性上的取值。

根据以上判别准则分别求出给定样本对每个分类的后验概率,其中最大的后验概率所对应的类即为该样本的分类。

显然,朴素贝叶斯分类器的训练过程就是基于训练集来估计类先验概率,并为每个属性估计条件概率。

令表示训练集中第类样本组成的集合,若有充足的独立同分布样本,则可容易地估计出类先验概率

对离散属性而言,令表示中在第个属性上取值为的样本组成的集合,则条件概率可估计为

对连续属性可考虑概率密度函数,假定, 其中和分别是对第类样本在第个属性上取值的均值和方差,则有

项目案例

这里使用周志华-机器学习里面的西瓜数据集-使用朴素贝叶斯分类器判断西瓜的好坏。
具体的数据集如下:

编号 色泽 根蒂 敲声 纹理 脐部 触感 密度 含糖率 好瓜
1 青绿 蜷缩 浊响 清晰 凹陷 硬滑 0.697 0.46 是
2 乌黑 蜷缩 沉闷 清晰 凹陷 硬滑 0.774 0.376 是
3 乌黑 蜷缩 浊响 清晰 凹陷 硬滑 0.634 0.264 是
4 青绿 蜷缩 沉闷 清晰 凹陷 硬滑 0.608 0.318 是
5 浅白 蜷缩 浊响 清晰 凹陷 硬滑 0.556 0.215 是
6 青绿 稍蜷 浊响 清晰 稍凹 软粘 0.403 0.237 是
7 乌黑 稍蜷 浊响 稍糊 稍凹 软粘 0.481 0.149 是
8 乌黑 稍蜷 浊响 清晰 稍凹 硬滑 0.437 0.211 是
9 乌黑 稍蜷 沉闷 稍糊 稍凹 硬滑 0.666 0.091 否
10 青绿 硬挺 清脆 清晰 平坦 软粘 0.243 0.267 否
11 浅白 硬挺 清脆 模糊 平坦 硬滑 0.245 0.057 否
12 浅白 蜷缩 浊响 模糊 平坦 软粘 0.343 0.099 否
13 青绿 稍蜷 浊响 稍糊 凹陷 硬滑 0.639 0.161 否
14 浅白 稍蜷 沉闷 稍糊 凹陷 硬滑 0.657 0.198 否
15 乌黑 稍蜷 浊响 清晰 稍凹 软粘 0.36 0.37 否
16 浅白 蜷缩 浊响 模糊 平坦 硬滑 0.593 0.042 否
17 青绿 蜷缩 沉闷 稍糊 稍凹 硬滑 0.719 0.103 否

根据色泽、根蒂、敲声、纹理、脐部、触感、密度、含糖率这些特征,对测试例1进行分类。

编号 色泽 根蒂 敲声 纹理 脐部 触感 密度 含糖率 好瓜
测1 青绿 蜷缩 浊响 清晰 凹陷 硬滑 0.697 0.46 ?

首先估计类先验概率,显然有

好瓜是

好瓜否

然后,为每个属性类估计条件概率:

青绿是色泽青绿好瓜是

青绿否色泽青绿好瓜否


密度是密度好瓜是

于是,对测试例1有:

好瓜是青绿是,蜷缩是,浊响是,清晰是,凹陷是,硬滑是,密度:,含糖:好瓜是青绿是蜷缩是浊响是清晰是凹陷是硬滑是密度:是含糖:是

好瓜否青绿是,蜷缩是,浊响是,清晰是,凹陷是,硬滑是,密度:,含糖:好瓜否青绿否蜷缩否浊响否清晰否凹陷否硬滑否密度:否含糖:否

由于,因此,朴素贝叶斯分类器将测试样本例1判别为好瓜。

纯手打代码

  1. import numpy as np
  2. from io import StringIO
  3. import pandas as pd
  4. import math
  5. def createDataSet():
  6. ''' 数据读入 '''
  7. rawData = StringIO(
  8. """编号,色泽,根蒂,敲声,纹理,脐部,触感,密度,含糖率,好瓜
  9. 1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.46,是
  10. 2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,0.774,0.376,是
  11. 3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,0.634,0.264,是
  12. 4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,0.608,0.318,是
  13. 5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,0.556,0.215,是
  14. 6,青绿,稍蜷,浊响,清晰,稍凹,软粘,0.403,0.237,是
  15. 7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,0.481,0.149,是
  16. 8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,0.437,0.211,是
  17. 9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,0.666,0.091,否
  18. 10,青绿,硬挺,清脆,清晰,平坦,软粘,0.243,0.267,否
  19. 11,浅白,硬挺,清脆,模糊,平坦,硬滑,0.245,0.057,否
  20. 12,浅白,蜷缩,浊响,模糊,平坦,软粘,0.343,0.099,否
  21. 13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,0.639,0.161,否
  22. 14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,0.657,0.198,否
  23. 15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,0.36,0.37,否
  24. 16,浅白,蜷缩,浊响,模糊,平坦,硬滑,0.593,0.042,否
  25. 17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,0.719,0.103,否
  26. """)
  27. df = pd.read_csv(rawData, sep=",")
  28. return df
  29. df = createDataSet()
  30. df.head()
  31. def st_norm(x,uci,eci):
  32. return 1.0/(math.sqrt(2*math.pi)*eci)*math.e**(-(x - uci)**2/(2*eci**2))
  33. def naive_bayes(data, feature):
  34. # 估计类先验概率
  35. N = len(data)
  36. res = {}
  37. P_pre = data['好瓜'].value_counts().apply(lambda x:'{0:.3f}'.format(x/N))
  38. res['好瓜'] = P_pre.values
  39. # 估计类条件概率
  40. for key, val in feature.items():
  41. if data[key].dtype.name == 'object':
  42. raw = data[data[key] == val]
  43. temp = raw.groupby('好瓜')[key].count().apply(lambda x:'{0:.3f}'.format(x/len(raw)))
  44. res[key] = temp.values
  45. else:
  46. raw = data
  47. temp = raw.groupby('好瓜')[key].apply(lambda x: st_norm(val ,x.mean(),x.std()))
  48. res[key] = temp.values
  49. # 输出最大概率分类
  50. df = pd.DataFrame(res, index=['好瓜:否', '好瓜:是'])
  51. return df.prod(axis=1).idxmax()
  52. naive_bayes(df, {'色泽':'青绿', '根蒂':'蜷缩', '敲声':'浊响', '纹理':'清晰', '脐部':'凹陷', '触感':'硬滑', '密度':0.697, '含糖率':0.460})

sklearn实现代码

  1. from sklearn.preprocessing import LabelEncoder
  2. from sklearn import datasets
  3. from sklearn.naive_bayes import GaussianNB
  4. # re-encoding
  5. for col in ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']:
  6. df[col] = LabelEncoder().fit_transform(df[col])
  7. gnb = GaussianNB()
  8. y_pred = gnb.fit(df[['色泽', '根蒂', '敲声', '纹理', '脐部', '触感', '密度', '含糖率']], df['好瓜']).predict(df[['色泽', '根蒂', '敲声', '纹理', '脐部', '触感', '密度', '含糖率']])
  9. print('Number of mislabeled points out of a total {0} points : {1}'.format(len(y_pred), sum(y_pred != df['好瓜'])))
  10. >> Number of mislabeled points out of a total 17 points : 3

拉普拉斯修正

注意,若某个属性值在训练集中没有与某个类同时出现过,则直接基于按频率估计概率,再进行判别会出现问题。例如在上述西瓜数据集训练朴素贝叶斯分类器时,对一个“敲声=清脆”的测试例,有

清脆是敲声清脆好瓜是

由于连乘之后计算出的概率为零,无论该样本的其他属性是什么,哪怕其他属性明显像好瓜,分类的结果都将是“好瓜=否”,这样显然不合理。

为了避免其他属性携带的信息被训练集中未出现的属性值“抹去”,在估计概率值时通常进行“平滑”,常用“拉普拉斯修正”。具体来说,令表示训练集中可能的类别数,表示第个属性可能的取值数,修正公式为:


例如,在上面的例子中,类先验概率可估计为

好瓜是

好瓜否

参考文档

机器学习-周志华
第4章 基于概率论的分类方法:朴素贝叶斯
统计学习方法-李航

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注