朴素贝叶斯算法

朴素贝叶斯(Naive Bayes,以下简称NB)算法是基于概率学习的一种分类方法,朴素贝叶斯利用先验信息来预测将来事件发生的概率。举个例子,就好比古时大夫给病人看病,他需要“望闻问切”,才能对病人的病情做出诊断。这里“望闻问切”是为了获取病人的病情即特征,然后他会对比该病情特征和以往他所见过的病情特征做比较,推断具体病症然后对症下药,这里的推断从某种程度上就用到了贝叶斯算法。好了,下面进入主题,介绍什么是NB算法。

NB算法的基础是贝叶斯定理,我们首先来理解一下贝叶斯定理的定义。

贝叶斯定理

我们直接抛出贝叶斯定理公式:


这里对其中的一些记号做一些说明,表示条件概率,即事件B发生的前提下A发生的概率。

接下来说说这个公式的妙用了,我们在实际问题中经常遇到很难直接得到,而很容易求得的情形,这时便可采用贝叶斯定理了。

为了便于理解上面的贝叶斯定理,我们引用一个典型的垃圾邮件分类问题。

把问题做简化,假设只有一个分类特征,获得如下频数表信息,行spam表示垃圾邮件,ham表示正常邮件,yes表示邮件中出现free单词,no表示邮件中未出现free单词。接下来,我们看如何用朴素贝叶斯算法来判断新来邮件是否为垃圾邮件。

freq yes no Total
spam 15 5 20
ham 10 70 80
Total 25 75 100

假如新来一封邮件,我们在未获取任何特征信息的时,认为这封邮件是垃圾邮件的概率为20%(历史样本中垃圾邮件的比例)。这里的被称之为先验概率。

如果我们获取了特征信息,知道这封邮件中是否含有free单词,那么我们可以计算出或者,这个条件概率称之为似然,与之对应的 或者则称之为边缘似然。

有了以上这些概率值,我们便可很容易的求得后验概率,公式如下,


同理,我们可以计算出,然后比较其与的大小,哪一项概率值更大,那么邮件则更可能属于哪一类。

这时,新来一封邮件,经统计发现,该邮件内容中出现了free单词,我们首先按步骤计算似然、边缘似然以及先验概率:


然后计算后验概率:

于是,我们判定这封邮件为垃圾邮件。下面对NB算法的一般步骤做个总结。

NB算法
NB分类计算步骤
  • 1 获取特征属性值 ,设表示类别

  • 2 计算条件概率 ,先验概率,以及边缘似然

  • 3 由贝叶斯公式计算

  • 4 计算 ,则

这里计算的关键是计算条件概率

  • 当特征属性为离散情形时, 非常容易计算,只要统计各个离散的特征属性值在每种分类中出现的频率即可;

  • 当特征为连续特征时,可以把连续特征离散化,离散化后计算规则同上;更一般地,我们假定其值服从正态分布。即

这里的为特征类别下的样本均值和标准差。


正态分布的好处是分布参数容易估计,大多数特征属性在大样本情形下用正态分布不会有太大的问题。实际上,这里的分布形式并不局限于正态分布,确切地说,为提高分类的准确度,我们应当采用更适合的特征属性的分布形式。

Laplace校准

当特征属性为离散情形时,当其中一个类别下某个特征划分没有出现即

这时假定特征之间相互独立,那有

这可能会导致严重的预测错误。我们来看个例子:

这时,判定属于C1类的概率为

判定属于C2类的概率为

这种判定合理吗,很可能不是的。

这便是Laplace估计量设计的初衷,引入它就是用来防止这类问题的发生。Laplace校准的思想非常简单,就是对每个类别下所有划分的统计频数加一个小的常数,这个常数通常设为1,就是为了保证在每一种分类情况下,其特征的统计频数不为0。回过头来,在上述例子中加入Laplace=1,重新计算分类概率:

我们看到,经Laplace校正,判定属于C1类的概率为

判定属于C2类的概率为

可以看到,判定结论来了个大翻转,而这个判定才极有可能是最终正确的。

编写一个NB算法程序

数据采用案例数据中的asdat数据集(参见微信公众号),尝试编写一个NB算法来实现预测全明星的归属的目的。不多说,直接上代码:

# 设随机数种子   
set.seed(123)
# 拆分训练和测试集      
as.ind <- which(asdat$player %in% allStarnames[-c(3,6,9,12,15,18,21,24)])
no.ind <- which(!asdat$player %in% allStarnames)
train.index <- c(as.ind,sample(no.ind, length(no.ind)%/%4*3))
asdat.train <- asdat[train.index, ]asdat.test <- asdat[-train.index, ]

# 计算概率密度函数的参数
density.M <- ddply(.data = asdat.train,
.variables = "as",                  
.fun = function(dat) data.frame(feature=c("pts","per","wr"),
m=c(mean(dat$pts),mean(dat$per),mean(dat$wr)),
sd=c(sd(dat$pts),sd(dat$per),sd(dat$wr)))  )

# 先验概率
prior.p <- sum(asdat.train$as==1)/nrow(asdat.train)
# 朴素贝叶斯分类预测
predict.nb <- function(newdata,density.M,prior.p){  # 提取不同类别概率密度函数的参数  density.pts0 <- filter(density.M,feature=="pts" & as==0)  density.per0 <- filter(density.M,feature=="per" & as==0)  density.wr0 <- filter(density.M,feature=="wr" & as==0)  density.pts1 <- filter(density.M,feature=="pts" & as==1)  density.per1 <- filter(density.M,feature=="per" & as==1)  density.wr1 <- filter(density.M,feature=="wr" & as==1)  n <- nrow(newdata)  pred <- rep(NA,n)  for(i in 1:n){    temp <- newdata[i,]    # 计算负类概率    f1_C0 <- dnorm(temp$pts,mean = density.pts0$m,sd = density.pts0$sd)    f2_C0 <- dnorm(temp$per,mean = density.per0$m,sd = density.per0$sd)    f3_C0 <- dnorm(temp$wr,mean = density.wr0$m,sd = density.wr0$sd)    p0 <- f1_C0*f2_C0*f3_C0*(1-prior.p)        # 计算正类概率    f1_C0 <- dnorm(temp$pts,mean = density.pts1$m,sd = density.pts1$sd)    f2_C0 <- dnorm(temp$per,mean = density.per1$m,sd = density.per1$sd)    f3_C0 <- dnorm(temp$wr,mean = density.wr1$m,sd = density.wr1$sd)    p1 <- f1_C0*f2_C0*f3_C0*prior.p        # 判定    pred[i] <- ifelse(p1>p0,1,0)  }  return(pred)
}

# 检验预测结果
pred <- predict.nb(asdat.test,density.M,prior.p)
table(pred,asdat.test$as)
 
## pred  0  1
##    0 23  3
##    1  1  5
# 预测错误项
asdat.test$pred <- pred
select(asdat.test,player,as,pred) %>% filter(as!=pred)
##          player as pred
## 1 达米安-利拉德  0    1
## 2   德维恩-韦德  1    0
## 3 科比-布莱恩特  1    0
## 4   艾尔-霍福德  1    0

可以看到,预测的准确率还可以。有意思的是,NB算法预测结果与基于kNN预测全明星归属(←点此链接可跳转)的预测结果那完全一样,预测效果可接受,分析参见前篇。

上述案例可以帮你深入理解贝叶斯分类算法的计算流程,但是程序代码写得比较粗糙,仅适用于这个特定案例。其实,当你十分熟悉NB算法后,也可以直接调用e1071包中的naiveBayes函数,其调用形式相当简单,留给大家自行尝试,有任何问题欢迎交流,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值