python机器学习——朴素贝叶斯算法

背景与原理:

朴素贝叶斯算法是机器学习领域最经典的算法之一,仍然是用来解决分类问题的。

那么对于分类问题,我们的模型始终是:用m组数据,每条数据形如(x1,...,xn,y),表示数据共有n个特征维度,而y表示该数据所属的类别,不妨设有k个取值C1,...,Ck

我们想一想,当我们谈论分类问题的时候,我们究竟在谈论什么?

从一个角度来理解,我们实际上是在研究:当给定了X=x的条件下,求概率P(y=Ci),而我们对分类的预测实际上就是使得P(y=Ci)最大的Ci

那么我们实际想求出的是P(y=Ci|X=x)这样的一个条件概率。

我们需要一些数学原理:

贝叶斯公式:P(X|Y)=P(Y|X)P(X)P(Y)

这个公式的逻辑是很简单的:P(XY)=P(X|Y)P(Y)=P(Y|X)P(X),即两个事件同时发生的概率始终等于一个事件在另一个事件发生条件下的概率乘以另一个事件发生的概率。

而基于这个逻辑,我们有:

P(y=Ci|X=x)=P(X=x|y=Ci)P(y=Ci)P(X=x)

而我们再要求X的各个特征是彼此独立的,那么我们有:

P(X=x|y=Ci)=j=1nP(Xj=xj|y=Ci)

于是我们有最终的表达式:

P(y=Ci|X=x)=j=1nP(Xj=xj|y=Ci)P(y=Ci)P(X=x)

而我们想要的是:

argmaxCij=1nP(Xj=xj|y=Ci)P(y=Ci)P(X=x)

可以看到,对不同的Ci,上式的分母是相同的,那么我们将其省略,就得到了:

argmaxCiP(y=Ci)j=1nP(Xj=xj|y=Ci)

这就是我们真正想求的东西

那么P(y=Ci)是多少呢?它是一个无关条件的先验概率,那么我们可以估计其为数据集中类别为Ci的数据出现的频率,即出现次数与数据集大小之比。那么我们设数据集中类别为Ci的数据有ci条,那么我们有:

P(y=Ci)=cim(其中m为数据集大小)

但是如果我们数据集选取的很不好,某一个类别虽然我们的先验知识告诉我们有,但数据集中却没有这一个分类,这只能说明这个类别出现概率可能比较小,但并不意味着一定不会出现,所以我们需要给一个补偿项,我们选取一个常数λ,有:

P(y=Ci)=ci+λm+kλ(其中k为类别数,相当于对每一类我们都人工添加了λ个属于这一类的数据)

这样兜兜转转,我们发现不太好求出的实际上是P(Xj=xj|y=Ci)

那么怎么求呢?如果Xj是一个离散的量,那么我们只需再次引入贝叶斯公式:

P(Xj=xj|y=Ci)=P(Xj=xj,y=Ci)P(y=Ci)

这样我们只需统计在原数据集中Xj=xjy=Ci的数据集出现的频率近似为概率再除以y=Ci出现的概率就好了。

当然,和上面的情况一样,我们同样可能会遇到倒霉的情况,即这种数据没有出现在数据集中,那我们当然也不能直接认为这种概率是零,那么和上述处理类似地引入拉普拉斯平滑,选取一个常数λ(通常为1),此时有:

P(Xj=xj|y=Ci)=p=1m[Xj=xj,y=Ci]+λp=1m[y=Ci]+Ojλ

这里的记号[...]表示如果中括号里内容为真取值为1,否则取值为0,而Oj是特征j的取值个数

但是...如果特征是连续的呢?

那么我们会认为这样的分布服从正态分布,即这个条件概率为:

P(Xj=xj|y=Ci)=12πσi2e(xjμi)22σi2

即我们认为在y=Ci的条件下,所有的Xj的分布服从均值为μi,方差为σi2的正态分布,而这个均值与方差可以通过极大似然估计求得。

这样我们就解决了所有的问题。

代码实现:

复制代码
import numpy as np
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import LinearSVC
import matplotlib.pyplot as plt
import pylab as plt
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split


X,y=datasets.make_classification(n_samples=10000,n_features=20,n_informative=2,n_redundant=2)
X_train,X_test,Y_train,Y_test=train_test_split(X,y,test_size=0.25)

lr=LogisticRegression()
svc=LinearSVC(C=1.0)
rfc=RandomForestClassifier(n_estimators=100)#森林中树的个数

lr=lr.fit(X_train,Y_train)
score1=lr.score(X_test,Y_test)
print(score1)

svc=svc.fit(X_train,Y_train)
score2=svc.score(X_test,Y_test)
print(score2)

rfc=rfc.fit(X_train,Y_train)
score3=rfc.score(X_test,Y_test)
print(score3)

gnb=GaussianNB()
gnb=gnb.fit(X_train,Y_train)
score4=gnb.score(X_test,Y_test)
print(score4)

y_pred=gnb.predict_proba(X_test)
print(y_pred[:10])
复制代码

这是在上一篇博客基础上对四种分类器的对比,在sklearn中朴素贝叶斯分类器主要有三种:高斯朴素贝叶斯GaussianNB,多项式朴素贝叶斯MultinomialNB和伯努利朴素贝叶斯BernoulliNB,高斯朴素贝叶斯用于处理特征是连续值的情况,而多项式朴素贝叶斯用于处理特征是离散值的情况,而伯努利朴素贝叶斯则用于处理特征只有0/1的情况。

这里我们使用sklearn自带的高斯朴素贝叶斯对与前文类似生成的数据集进行分类并对比分类效果,可以看到由于朴素贝叶斯对特征的分布有严格的要求(独立、正态等),因此分类效果相较别的分类器相对较差,但是朴素贝叶斯的训练效率比较高,而且可解释性也比较好,这是朴素贝叶斯的优点所在。

小结与优化:

朴素贝叶斯由于基础要求太高,导致很多情况下分类效果并不好,那么为了解决这个问题,人们作出了一些优化。比如针对要求各个维度相互独立的要求,一种方法是在朴素贝叶斯基础上增加属性间可能存在的依赖关系,另一种则是重新构建数据集,通过变换等手段将原来相关的属性变为独立的属性。最著名的优化方法是TAN算法,通过发现属性间的依赖关系来降低独立性假设。

posted @   lleozhang  Views(397)  Comments(0Edit  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
levels of contents
点击右上角即可分享
微信分享提示