分享

机器学习之朴素贝叶斯垃圾邮件分类

本帖最后由 regan 于 2016-9-12 17:57 编辑



贝叶斯分类方法是基于概率的分类方法,它可以预测类隶属关系的概率。贝叶斯分类基于贝叶斯定理。
贝叶斯公式为:
74.png
P(H|X),给定X的属性描述,找出元组X属性H的概率。P(H|X)是后验概率,即在条件X的情况下H的概率。有了理论基础,怎么应用该理论分类呢?
1.设D是训练元组和他们相关联的类标号的集合。通常每个元组用一个n维属性向量X={x1,x2,x3.....xn}表示,描述由n个属性A1、A2、A3....An对元组的n个测量
2.假定有m个类,C1,C2,C3....Cm。给定元组X,分类法将预测X属于具有最高后验概率的类。也就是说,朴素贝叶斯预测X属于类Ci,当且仅当P(Ci|X)>P(Cj|X), 1=<  j <=m;i!=j。这样最大化P(Ci|X)。P(Ci|X)最大的类Ci称为最大后验假设。由贝叶斯定理
P(Ci|X)=(P(Ci)*P(X|Ci))/(P(X))

3.由于P(X)对所有类为常数,所以只需要P(Ci)*P(X|Ci)最大即可。如果类的先验概率未知,则假设这些类是等概率的,即P(C1)=P(C2)=P(C3).....P(Cm),并据此使P(X|Ci)最大化;若不是等概率的,则最大化P(Ci)*P(X|Ci)。
注意*:类先验概率可以由|C[i,D]|/|D估计,其中|C[i,D]|是D中Ci类的元组的个数

4.给定具有很多属性的数据集,计算P(X|Ci)的开销可能非常大。为了降低P(X|Ci)的计算开销,可以做类条件独立的朴素假定。给定元组的类标号,假定属性值有条件的相互独立(即属性之间不存在相互的依赖关系),因此有上式。
可以很容易的由训练元组估计概率P(x1|Ci),P(x2|Ci).....P(Xn|Ci)。注意*:Xk表示元组X在属性Ak的值。对于每个属性,还要考虑属性是分类的还是连续的。考虑如下:
a.如果Ak是分类的属性,则P(Xk|Ci)是D中属性Ak的值为Xk的Ci类的元组数除以D中Ci的元组数|C[i,D]|
b.如果Ak是连续的属性,需要多做一些工作。通常假设连续值属性服从均值为u,标准差为@的高斯分布。

75.png
5.为了预测X的类标号,对每个类Ci,计算P(X|Ci)P(Ci)。该分类法预测输入元组X的类为Ci,当且仅当
P(X|Ci)P(Ci) > P(X|Cj)P(Cj) , 1<=j<=m;j!=i
换言之,被预测的类标号是使P(X|Ci)P(Ci)最大的类Ci


来看看朴素贝叶斯用于垃圾邮件分类的例子,该例子为R语言。
我们知道,邮件要么为垃圾邮件,要么为正常邮件。怎么做呢?
第一步:这里我们假设垃圾邮件和正常邮件的概率为0.5。此处的0.5即为我们对垃圾和正常邮件的先验概率,当然这个概率可以动态调整。


第二部:加载训练数据。为了能够区分出垃圾邮件,首先得有垃圾邮件、正常邮件的数据。要使准确率越高,训练数据集应该越大越好。分别加载垃圾邮件和正常邮件,得到两个TDM(term document matrics),TDM中的[i,j]表示单词i在第j个文档中出现的次数。R代码如下。
get.tdm <- function(doc.vec){
  control <- list(stopwords = TRUE,
                  removePunctuation = TRUE,
                  removeNumbers = TRUE,
                  minDocFreq = 2)
  doc.corpus <- Corpus(VectorSource(doc.vec))
  doc.dtm <- TermDocumentMatrix(doc.corpus, control)
  return(doc.dtm)
}
接下来需要计算每个单词在每个文档的出现率和密度,并使用transform操作,将密度和出现率增加到df中。

occurrence <- sapply(1:nrow(matrix),function(i) {length(which(matrix[i,] > 0))/ncol(matrix)})
density <- df$frequency/sum(df$frequency)
df <- transform(spam.df, density=density,
occurrence=occurrence)




第三步:编写朴素贝叶斯函数,计算邮件属于垃圾邮件的概率。

classify.email <- function(path, training.df, prior=0.5, c=1e-6) {        msg <- get.msg(path)
        msg.tdm <- get.tdm(msg)
        msg.freq <- rowSums(as.matrix(msg.tdm))
       # Find intersections of words
        msg.match <- intersect(names(msg.freq), training.df$term)
      if(length(msg.match) < 1) {
         return(prior*c^(length(msg.freq)))
      }
     else {
       match.probs <- training.df$occurrence[match(msg.match,                  training.df$term)]
        return(prior * prod(match.probs) * c^(length(msg.freq)-length(msg.match)))
}
}

classify.email这个function接受四个参数,第一个参数是被分类邮件的存放路径,第二个参数是训练得到的训练集,第三个参数是先验概率,默认为0.5,可配置。第四个参数表示邮件中的单词不在训练集中的概率,该值通常设置得很小,因为我们不知道被检查邮件中的单词是否在训练集中存在,如果存在那好说;倘若不存在的话,这个概率怎么算,不可能设置成0,因为如果设置成0,贝叶斯公式基于乘法运算,那运算结果也是0.因此这个地方我们通过假定的方式,假定被检测邮件中单词不在测试数据集中的概率是一个很小的值,如:e-6。这种校准方法又叫做拉普拉斯校验法,避免零值的出现。



第四步:使用构建的朴素贝叶斯分类器,分类垃圾邮件
分别将被检测邮件使用垃圾邮件训练集和正常邮件训练集,通过第三步写的classify.email方法算出是垃圾邮件和正常邮件的概率,比较两个概率,若垃圾邮件的概率大于正常邮件的概率,则将被检测邮件标记为垃圾邮件,否则标记为正常邮件。

hardham.spamtest <- sapply(hardham.docs,       function(p) classify.email(paste(hardham.path, p, sep=""),
       training.df=spam.df))
hardham.hamtest <- sapply(hardham.docs,
      function(p) classify.email(paste(hardham.path, p, sep=""),
      training.df=easyham.df))
hardham.res <- ifelse(hardham.spamtest > hardham.hamtest, TRUE,         FALSE)
summary(hardham.res)




第五步:使用测试数据集测试邮件被正常分类的比例




第六步:调整先验概率,如垃圾邮件的先验概率调整为0.2,正常邮件的先验概率调整为0.8重复第4~6步直到正确分类的比例达到合理的范围。

已有(1)人评论

跳转到指定楼层
kirk 发表于 2017-3-7 15:17:46
赞,楼主分析的很好,就是自己基础太差,程序不太懂
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条