@77qingliu
2018-04-24T09:15:39.000000Z
字数 5318
阅读 1207
machine-learning
python
朴素贝叶斯(Naive Bayes)是基于贝叶斯公式与特征条件独立的建设,估计后验概率,根据后验概率进行分类的监督学习方法。对于给定的训练数据集,首先基于特征条件独立的假设学习输入/输出的联合概率分布;然后基于此模型,对给定的输入,利用贝叶斯公式求出后验概率最大的输出。
类先验概率表达了样本占空间中各类样本所占的比例,根据大数定理,当训练集中包含充足的独立同分布样本时,可以通过各类样本的频率进行估计。这里其实是极大似然估计的思想。
对类条件概率来说,由于涉及关于的所有属性的联合概率,直接根据样本出现的频率进行估计将会出现严重困难。例如,假设样本中的个属性都是二值的,则样本空间中将有种可能的取值。很多样本取值在训练集中根本没有出现,直接用频率来估计是不可行的。为避开这个障碍,“朴素贝叶斯分类器”采用了“属性条件独立性假设”:对已知的类别,假设所有属性相互独立。换言之,假设每个属性独立地对分类结果产生影响。
基于条件独立性的假设,可重写为:
根据以上判别准则分别求出给定样本对每个分类的后验概率,其中最大的后验概率所对应的类即为该样本的分类。
显然,朴素贝叶斯分类器的训练过程就是基于训练集来估计类先验概率,并为每个属性估计条件概率。
令表示训练集中第类样本组成的集合,若有充足的独立同分布样本,则可容易地估计出类先验概率
对离散属性而言,令表示中在第个属性上取值为的样本组成的集合,则条件概率可估计为
对连续属性可考虑概率密度函数,假定, 其中和分别是对第类样本在第个属性上取值的均值和方差,则有
这里使用周志华-机器学习里面的西瓜数据集-使用朴素贝叶斯分类器判断西瓜的好坏。
具体的数据集如下:
编号 | 色泽 | 根蒂 | 敲声 | 纹理 | 脐部 | 触感 | 密度 | 含糖率 | 好瓜 |
---|---|---|---|---|---|---|---|---|---|
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判别为好瓜。
纯手打代码
import numpy as np
from io import StringIO
import pandas as pd
import math
def createDataSet():
''' 数据读入 '''
rawData = StringIO(
"""编号,色泽,根蒂,敲声,纹理,脐部,触感,密度,含糖率,好瓜
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,否
""")
df = pd.read_csv(rawData, sep=",")
return df
df = createDataSet()
df.head()
def st_norm(x,uci,eci):
return 1.0/(math.sqrt(2*math.pi)*eci)*math.e**(-(x - uci)**2/(2*eci**2))
def naive_bayes(data, feature):
# 估计类先验概率
N = len(data)
res = {}
P_pre = data['好瓜'].value_counts().apply(lambda x:'{0:.3f}'.format(x/N))
res['好瓜'] = P_pre.values
# 估计类条件概率
for key, val in feature.items():
if data[key].dtype.name == 'object':
raw = data[data[key] == val]
temp = raw.groupby('好瓜')[key].count().apply(lambda x:'{0:.3f}'.format(x/len(raw)))
res[key] = temp.values
else:
raw = data
temp = raw.groupby('好瓜')[key].apply(lambda x: st_norm(val ,x.mean(),x.std()))
res[key] = temp.values
# 输出最大概率分类
df = pd.DataFrame(res, index=['好瓜:否', '好瓜:是'])
return df.prod(axis=1).idxmax()
naive_bayes(df, {'色泽':'青绿', '根蒂':'蜷缩', '敲声':'浊响', '纹理':'清晰', '脐部':'凹陷', '触感':'硬滑', '密度':0.697, '含糖率':0.460})
sklearn实现代码
from sklearn.preprocessing import LabelEncoder
from sklearn import datasets
from sklearn.naive_bayes import GaussianNB
# re-encoding
for col in ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']:
df[col] = LabelEncoder().fit_transform(df[col])
gnb = GaussianNB()
y_pred = gnb.fit(df[['色泽', '根蒂', '敲声', '纹理', '脐部', '触感', '密度', '含糖率']], df['好瓜']).predict(df[['色泽', '根蒂', '敲声', '纹理', '脐部', '触感', '密度', '含糖率']])
print('Number of mislabeled points out of a total {0} points : {1}'.format(len(y_pred), sum(y_pred != df['好瓜'])))
>> Number of mislabeled points out of a total 17 points : 3
注意,若某个属性值在训练集中没有与某个类同时出现过,则直接基于按频率估计概率,再进行判别会出现问题。例如在上述西瓜数据集训练朴素贝叶斯分类器时,对一个“敲声=清脆”的测试例,有
为了避免其他属性携带的信息被训练集中未出现的属性值“抹去”,在估计概率值时通常进行“平滑”,常用“拉普拉斯修正”。具体来说,令表示训练集中可能的类别数,表示第个属性可能的取值数,修正公式为:
例如,在上面的例子中,类先验概率可估计为