贝叶斯分类算法介绍:
贝叶斯分类算法是统计学的一种概率分类方法,朴素贝叶斯分类是贝叶斯分类中最简单的一种。 其分类原理就是利用贝叶斯公式根据某特征的先验概率计算出其后验概率,然后选择具有最大后验概率的类作为该特征所属的类。之所以称之为"朴素",是因为贝叶斯分类只做最原始、最简单的假设:所有的特征之间是统计独立的。假设某样本X有a1, a2.,…an个属性,那么有P(X)= P(a1,a2…,an)= P(a1)* P(a2)… P(an),满足样的公式就说明特征统计独立。
条件概率公式
条件概率(Condittional probability), 就是指在事件B发生的情况下,事件A发生的概率,P(A| B)来表示。
根据文氏图可知:在事件B发生的情况下,事件A发生的概率就是 除以
等式两边同时乘以P(B),可以得到P(AB)的表现形式。 同理可得:
这就是朴素贝斯公式的表现形式
全概率公式:
接着看全概率公式,如果事件A1, A2, A… An构成一个完备事件且都有正概率,那么对于任意一个事件B则
贝叶斯推断
根据条件概率和全概率公式,可以得到贝叶斯公式如下:
当分类中有多个类别的时候我们采用第二种的贝叶斯计算公式来计算其概率。
**P(A)称为"先验概率" (Prior probability),即在B事件发生之前,我们对A事件概率的一个判断。
P(A| B)称为"后验概率" (Posterior probability),即在B事件发生之后,我们对A事件概率的重新评估。
P(B|A)/P(B)称为"可能性函数" (Likely hood),这是一个调整因子, 使得预估概率更接近真实概率。
所以条件概率可以理解为:后验概率=先验概率*调整因子
如果"可能性函数">1,意味着"先验概率"被增强,事件A的发生的可能性变大;
如果"可能性函数"=1,意味着B事件无助于判断事件A的可能性;
如果"可能性函数"<1,意味着"先验概率被削弱,事件A的可能性变小。
**
GaussianNB
GaussianNB就是先验为高斯分布(正态分布)的朴素贝叶斯,假设每个标签的数据都服从简单的正态分布:
其中 为Y的第k类类别。 和 为需要从训练集计算的值。分别表示数据的期望和方差。
MultinomialNB
MultinomialNB就是先验为多项式分布的朴素贝叶斯。它假设特征是由一个简单多项式分布生成的。 多项分布可以描述各种类型样本出现次数的概率,因此多项式朴素贝叶斯非常适合用于描述出现次数或者出现次数比例的特征。该模型常用于文本分类,特征表示的是次数,例如某个词语的出现次数。多项式分布公式如下:
上述式子表示:是第k个类别的第j维特征的第I个取值条件概率。mk是训练集中输出为第k类的样本个数。入为一个大于0的常数,常常取为1,即拉普拉斯平滑。也可以取其他值。
BernoulliNB
BernoulliNB就是先验为伯努利分布的朴素贝叶斯。假设特征的先验概率为二元伯努利分布,即如下式:
此时l两种取值。xjl只能取值0或者1。
在伯努利模型中,每个特征的取值是布尔型的,即true和false, 或者1和0。在文本分类中,就是一个特征有没有在一个文档中出现。
例子(以西瓜书上面的例子进行讲解):
训练样本:
测试样本:
朴素贝叶斯解决的步骤:
首先估计先验概率P©:
P(好瓜=是)=8/17=0.471
P(好瓜=否)=9/17=0.529
然后计算每一个属性的估计条件概率P(xi|c):
最后分别计算是好瓜和坏瓜的概率:
由于好瓜的概率大于坏瓜的概率,因此朴素贝叶斯分类器将测试样本判别为好瓜
代码实现
贝叶斯分类算法解决鸢尾花分类:
import pandas as pd
import numpy as np
import random
dataset=pd.read_csv('iris.txt',header=None);
# print(dataset.head())
#print(dataset)
def randSplist(dataset,rate):
l=list(dataset.index)#
random.shuffle(l);
dataset.index=l
n=dataset.shape[0]
m=int(n*rate)
train=dataset.loc[range(m),:];
test=dataset.loc[range(m,n),:]
dataset.index=range(dataset.shape[0]);
test.index=range(test.shape[0])
return train,test;
# #测试切分情况
# ceshi1=randSplist(dataset,0.8);
# print(ceshi1);
#构建朴素贝叶斯分类器
def gbg_fenleiqi(train,test):
labels=train.iloc[:,-1].value_counts().index
# print(labels);
mean=[]
std=[]
reasult=[]
for j in labels:
item=train.loc[train.iloc[:,-1]==j,:];
m=item.iloc[:,:-1].mean()
s=np.sum((item.iloc[:,:-1]-m)**2)/(item.shape[0])
mean.append(m);
std.append(s)
# print(mean);
# print(std)
means=pd.DataFrame(mean,index=labels)
stds=pd.DataFrame(std,index=labels);
# print(means);
# print(stds)
for j in range(test.shape[0]):
jset=test.iloc[j,:-1].tolist();
jprob=np.exp(-1*(jset-means)**2/(stds*2))/(np.sqrt(2*np.pi*stds));
# print(jprob)
#正态分布公式
prob=1;
for k in range(test.shape[1]-1):
prob*=jprob[k];
# print(prob)
cla=prob.index[np.argmax(prob.values)]
# print(cla)
# print('--------------------')
# print(cla)
reasult.append(cla);
test['predict']=reasult;
acc=(test.iloc[:,-1]==test.iloc[:,-2]).mean()
#计算预测准确率
print(f"模型的预测准确率为{acc}");
#return test;
#测试构建情况
# train,test=randSplist(dataset,0.8);
# ceshi2=gbg_fenleiqi(train,test);
# print(ceshi2);
#系统测试
for i in range(3):
train,test=randSplist(dataset,0.9);
ceshi1=gbg_fenleiqi(train,test);
由于鸢尾花数据集比较纯净,朴素贝叶斯对其分类效果比较好
用scikit-learn相关的包进行鸢尾花分类并比较高斯朴素贝叶斯、多项式分布朴素贝叶斯和伯努利朴素贝叶斯的效果
高斯朴素贝叶斯代码实现
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)
gnb = GaussianNB()
y_pred = gnb.fit(X_train, y_train).predict(X_test)
print("测试集数目为:%d 预测出错的数目为: %d" % (X_test.shape[0], (y_test != y_pred).sum()))
print('分类的准确率为%s'%(1-((y_test != y_pred).sum()/X_test.shape[0])));
结果:
多项式分布朴素贝叶斯代码实现
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import ComplementNB
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)
cnb = ComplementNB()
y_pred = cnb.fit(X_train, y_train).predict(X_test)
print("测试集数目为:%d 预测出错的数目为: %d" % (X_test.shape[0], (y_test != y_pred).sum()))
print('分类的准确率为%s'%(1-((y_test != y_pred).sum()/X_test.shape[0])));
结果:
伯努利朴素贝叶斯代码实现
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import BernoulliNB
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)
bnb = BernoulliNB()
y_pred = bnb.fit(X_train, y_train).predict(X_test)
print("测试集数目为:%d 预测出错的数目为: %d" % (X_test.shape[0], (y_test != y_pred).sum()))
print('分类的准确率为%s'%(1-((y_test != y_pred).sum()/X_test.shape[0])));
结果:
结论:
通过比较这三种方法的效果,我们可以得出高斯朴素贝叶斯对鸢尾花分类效果最好。
一般来说, 如果样本特征的分布大部分是连续值,使用GaussianNB会比较好。
如果如果样本特征的分布大部分是多元离散值,使用MultinomialNB比较合适。
而如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。
例子二:来对皮马印第安人糖尿病进行分类
我们采用的是皮马印第安人糖尿病数据集,共有九个字段,八个属性。
'''
皮马印第安人糖尿病数据集
怀孕次数
口服葡萄糖耐量试验中血浆葡萄糖浓度
舒张压(mm Hg)
三头肌组织褶厚度(mm)
2小时血清胰岛素(μU/ ml)
体重指数(kg/(身高(m))^ 2)
糖尿病系统功能
年龄(岁)
'''
代码实现:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import GaussianNB # 导入sklearn的贝叶斯算法
from sklearn.model_selection import train_test_split
data = pd.read_csv('pima-indians-diabetes.data',header=None)
# print(data);
# print(data.shape)
# panda的describe描述属性,展示了每一个字段的,
# 【count条目统计,mean平均值,std标准值,min最小值,25%,50%中位数,75%,max最大值】
# print(data.describe())
y = data[8]
X = data.iloc[:,0:8]
X_train,X_test,y_train,y_test = train_test_split(X,y,stratify=y,random_state=11)
nb = GaussianNB()
nb.fit(X_train,y_train)
print('准确率是:',nb.score(X_test,y_test))
为了检验随机因子对分类效果的影响,我们循环迭代随机因子(0-100),进行准确率的判断,并用可视化的将结果表示出来:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import GaussianNB # 导入sklearn的贝叶斯算法
from sklearn.model_selection import train_test_split
data = pd.read_csv('pima-indians-diabetes.data',header=None)
# print(data);
# print(data.shape)
# panda的describe描述属性,展示了每一个字段的,
# 【count条目统计,mean平均值,std标准值,min最小值,25%,50%中位数,75%,max最大值】
# print(data.describe())
y = data[8]
X = data.iloc[:,0:8]
x=range(100)
score_total=[]
index=0
max_acc=0
for i in range(100):
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=i)
nb = GaussianNB()
nb.fit(X_train, y_train)
score=nb.score(X_test, y_test)
print('准确率是:',score)
if score >=max_acc:
max_acc=score;
index=i;
score_total.append(score)
plt.plot(x,score_total,'yo-')
plt.show()
print('最大的准确率为:',max_acc,'随机因子为:',index)
结果:
部分结果如下:
可视化效果图:
由于不同的随机因子会导致模型的准群率的不同,因此我们在模型训练的同时要不断调整随机因子,使其的准确率达到最大化。
例子三(将上述的皮马印第安人糖尿病的分类分别用贝叶斯算法和逻辑回归来进行代码实现,来检验其效果)
代码实现;
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
data = pd.read_csv('pima-indians-diabetes.data',header=None)
y = data[8]
X = data.iloc[:,0:8]
X_train,X_test,y_train,y_test = train_test_split(X,y,stratify=y,random_state=11)
lr = LogisticRegression()
nb = GaussianNB()
lr_score = []
nb_score = []
train_sizes = range(10,len(X_train),10)
for train_size in train_sizes:
X_slice,_,y_slice,_ = train_test_split(X_train,y_train,train_size=train_size,stratify=y_train,random_state=11)
nb.fit(X_slice,y_slice)
nb_score.append(nb.score(X_test,y_test))
lr.fit(X_slice,y_slice)
lr_score.append(lr.score(X_test,y_test))
plt.plot(train_sizes,nb_score,label='native bayes')
plt.plot(train_sizes,lr_score,linestyle='--',label='logistic regression')
plt.xlabel('Number of training instances')
plt.ylabel('Test set accuracy')
plt.show()