本系列来自于我《人工智能》课程复习总结以及机器学习部分的实验总结
垃圾邮件分类是监督学习分类中一个最经典的案例,本文先复习了基础的概率论知识、贝叶斯法则以及朴素贝叶斯模型的思想,最后给出了垃圾邮件分类在Matlab中用朴素贝叶斯模型的实现
定义:事件B发生的情况下,事件A发生的概率记作条件概率 P(A|B)
条件概率也叫后验概率,无条件概率也叫先验概率(在没有任何其它信息存在的情况下关于命题的信度)
可以得到乘法规则:
推广有链式法则:
X是随机变量x取值集合,Y是随机变量y取值集合,那么称 P(X,Y) 为x和y的联合分布 P(X,Y)
边缘概率定义为联合分布中某一个随机变量发生的概率:
若事件A和B满足: P(A|B)=P(A) 或 P(B|A)=P(B) 或 P(A∧B)=P(A)P(B) ,则称A和B是独立的
称A和B关于C**条件独立**,则有:
从乘法规则 P(A∧B)=P(A|B)P(B)=P(B|A)P(A) 可以推导出贝叶斯法则:
经常我们把把未知因素cause造成的结果effect看作证据,去确定未知因素cause发生的概率,那么有:
P(effect|cause) 刻画了因果关系, P(cause|effect) 刻画了诊断关系。
举个例子:
我们预先知道在感冒(cause)的情况下头痛(effect)发生的概率为50%,而感冒的概率为0.025且头痛的概率为0.1,那么某天早上醒来我头痛了,这时我感冒的概率是0.5*0.025/0.1=0.125而不是感觉上的50%
给定cause的情况下有n个彼此条件独立的症状effect,那么他们的联合分布有:
通常称这个概率分布为朴素贝叶斯模型或贝叶斯分类器
那么朴素贝叶斯模型怎么实现分类呢?
我们设有很多种cause(m个),这些cause下分别会表现为n个effect(effect也有多种)。我们统计训练集(已做标记)的结果只能统计知道某个cause的情况下这n个effect的取值,也就是 P(effecti|causej),i=1,..,n,j=1,...,m ,以及这些cause分别的发生的概率 P(causej) 。那么当我们有未标记的测试数据需要预测时,只需要输入这些测试数据的表现,也就是n个effect,我们就能通过一下公式计算出条件概率最大的 causej 作为我们的预测:
之所以称之为朴素,是因为其对effect条件独立性的假设,但是往往实际情况中effect并非条件独立的。
假设:
模型:
我们需要用训练集计算出:
那么我们根据朴素贝叶斯模型即可计算出 P(spam|word1,...,wordn) ,选取一个threshold,若测试集某邮件的 P(spam|word1,...,wordn)>threshold 则标记该邮件为垃圾邮件
用Matlab实现朴素贝叶斯模型垃圾邮件分类器如下:
function [ypred,accuracy]= nbayesclassifier (traindata, trainlabel, testdata, testlabel, threshold)
trainnum = size(traindata, 1);
wordnum = size(traindata, 2);
p = zeros(wordnum, 2, 2);
count = zeros(2, 1);
for i = 1 : trainnum
count(trainlabel(i) + 1) = count(trainlabel(i) + 1) + 1;
for j = 1 : wordnum
p(j, trainlabel(i) + 1, traindata(i, j) + 1) = p(j, trainlabel(i) + 1, traindata(i, j) + 1) + 1;
end
end
pnorm = count(1) / trainnum;
pspam = count(2) / trainnum;
p(:, 1, :) = (p(:, 1, :)+1) / (count(1)+1);
p(:, 2, :) = (p(:, 2, :)+1) / (count(2)+1);
testnum = size(testdata, 1);
ypred = zeros(testnum, 1);
correct = 0;
for i = 1 : testnum
q = pnorm / pspam;
for j = 1 : wordnum
q = q * p(j, 1, testdata(i, j) + 1) / p(j, 2, testdata(i, j) + 1);
end
q = 1 / (1 + q);
if q > threshold
ypred(i) = 1;
end
if ypred(i) == testlabel(i)
correct = correct + 1;
end
end
accuracy = correct / testnum;
end
其中有几个要点:
p(:, 1, :) = (p(:, 1, :)+1) / (count(1)+1);
是为了避免某个单词在某个分类(正常邮件或垃圾邮件)中一直没有出现而导致p(:, 1, :)=0
的情况降低分类器鲁棒性的情况(称之为Laplace校准,在数据规模较大时,加1产生的偏差忽略不计)通过枚举threshold的可以确定在某个训练集和测试集划分下,最优的阈值选取
我简单测试1000个邮件的数据量,6:4划分下最优预测准确率只有90%(待优化)