朴素贝叶斯分类器
基本概念
朴素贝叶斯分类器计算一个样本属于某一类的概率(后验概率),进而比较概率大小来决定样本的分类结果。分类器需要数据集作为已知样本集,还需要这些样本的分类结果,最后对新给出的样本集进行分类。
具体来说,假设已经得到样本集 \(D=\{x_1,\cdots,x_n\}\) ,每一个 \(x_i\) 都有 \(k\) 个特征,分别记为 \(a_i\) , 可能类别为 \(Y=\{y_1,\cdots,y_m\}\) ,根据每个 \(x_i\) 的特征,它会被分类到某一个 \(y_j\) 类中。
现在我们已经知道 \(D\) 分类的结果,分类器需要根据已经有的这些信息对新的样本 \(x=(a_1,\cdots,a_k)\) 进行分类。换句话说, \(y_j\) 就是一些模型,我们需要根据现有分类数据判断 \(x\) 最有可能符合哪一个模型。
离散分类
需要计算已知 \(x\) 时分类到 \(y_j\) 的概率 \(\Pr(y_j|x)\) ,然后比较其中最大的概率,选择对应的 \(y_j\) 作为分类结果。根据贝叶斯公式
与先前类似,其中 \(\Pr(x)\) 可以忽略,我们用 \(D\) 中分类到 \(y_j\) 的元素占 \(D\) 所有元素的比例来估计 \(y_j\) 出现的概率 \(\Pr(y_j)\) 。
于是重点就在于计算 \(\Pr(x|y_j)\) ,我们知道 \(x\) 有一些特征,那么
也就是 \(x\) 的每一个特征都出现在 \(y_j\) 中的概率,其中 \(\Pr(a_i|y_j)\) 是 \(a_i\) 出现在 \(y_j\) 分类中的比例。最终就得到
计算右边的最大值,然后选择对应的 \(y_j\) 作为分类结果即可。
以下面离散数据集的代码为例,首先给出已知数据
fea_dis = [[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3]',[1,2,2,1,1,1,2,2,3,3,3,2,2,3,3]']; % 已经分类的数据集
gnd_dis = [-1,-1,1,1,-1,-1,-1,1,1,1,1,1,1,1,-1]'; % 对应的分类结果集
需要对 \((a_1,a_2)=(2,1)\) 进行分类,可以看出有 \(-1,1\) 两类,记为 \(y_1,y_2\)
target_dis = [2,1];
因此需要计算每个分类中不同特征出现的概率
用一个矩阵来存放上面的概率
% 记录概率 P(a_i|y_j)
P = zeros(2,2);
% 统计 1 和 -1 两类分别有多少元素
p_count1 = sum(gnd_dis == 1);
p_count2 = sum(gnd_dis == -1);
% x = (a1,a2) = (2,1)
% 统计 1 类中 2 和 1 出现的概率
P(1,1) = sum(fea_dis(:,1) == 2 & gnd_dis == 1) / p_count1;
P(1,2) = sum(fea_dis(:,2) == 1 & gnd_dis == 1) / p_count1;
% 统计 -1 类中 2 和 1 出现的概率
P(2,1) = sum(fea_dis(:,1) == 2 & gnd_dis == -1) / p_count2;
P(2,2) = sum(fea_dis(:,2) == 1 & gnd_dis == -1) / p_count2;
然后计算出似然估计
p1 = P(1,1) * P(1,2) * p_count1 / (p_count1 + p_count2);
p2 = P(2,1) * P(2,2) * p_count2 / (p_count1 + p_count2);
比较两个概率的大小决定分到哪一类即可。
连续分类
对于连续数据,通常是将其转化为离散数据集,包括两种方法
- 将特征取值范围分成几个较少的区间
- 假设每个类别中样本特征服从不同期望方差下的正态分布
第一种方法下,直接使用上面的方案即可;如果是第二种方法,我们假定 \(y_j\) 类中出现的特征 \(a_i\) 服从正态分布
这样就可令 \(\Pr(a_i|y_j) = g(a_i,\mu,\sigma)\) ,其中 \(\mu\) 和 \(\sigma^2\) 是 \(y_j\) 中出现的特征 \(a_i\) 的期望和方差。我们用平均值来近似期望,使用无偏方差
假定不同特征的协方差为 \(0\) ,也就是它们相互独立。
我们生成一个连续数据集
% 生成连续数据
mu = [0,2];
sigma = [1 0;0,1];
r1 = mvnrnd(mu,sigma,200);
target_r1 = mvnrnd(mu,sigma,10);
mu = [3,6];
sigma = [1 0;0,1];
r2 = mvnrnd(mu,sigma,200);
target_r2 = mvnrnd(mu,sigma,10);
% 数据集
fea_con = [r1;r2];
gnd_con = [ones(200,1);-1*ones(200,1)];
target_con = [target_r1;target_r2];
% 清除无用数据
clear mu sigma r1 r2 target_r1 target_r2
这里是利用二元正态分布生成了两组数据集,分别为 \(1,-1\) 类,然后将它们拼在一起,不过这不重要。
这次要对 \(10\) 个样本进行分类,还是按照之前的方法计算 \(\Pr(y_j)\) ,而 \(\Pr(a_i|y_j)\) 则采用上面的正态分布估计,就得到
% 统计 1 和 -1 两类分别有多少元素
p_count1 = sum(gnd_con == 1);
p_count2 = sum(gnd_con == -1);
% 获取 1 类和 -1 类的元素
y1 = fea_con(gnd_con == 1,:);
y2 = fea_con(gnd_con == -1,:);
% 计算平均值作为期望
mu1 = [mean(y1(:,1)) mean(y1(:,2))];
mu2 = [mean(y2(:,1)) mean(y2(:,2))];
% 计算方差
sigma1 = [(y1(:,1) - mu1(1))' * (y1(:,1) - mu1(1)) / (p_count1 - 1) 0;
0 (y1(:,2) - mu1(2))' * (y1(:,2) - mu1(2)) / (p_count1 - 1)];
sigma2 = [(y2(:,1) - mu2(1))' * (y2(:,1) - mu2(1)) / (p_count2 - 1) 0;
0 (y2(:,2) - mu2(2))' * (y2(:,2) - mu2(2)) / (p_count2 - 1)];
% 目标长度
n = length(target_con);
% 记录概率 P(a_i|y_j) 通过正态分布估计
P = zeros(2,2);
res = zeros(n,1);
% x = (a1,a2)
for i = 1:n
% 当前元素的两个特征
a1 = target_con(i,1);
a2 = target_con(i,2);
% 计算 1 类中 a1 a2 的概率
P(1,1) = 1 / sqrt(2*pi) / sigma1(1,1) * exp(-(a1-mu1(1))^2/(2 * sigma1(1,1)^2));
P(1,2) = 1 / sqrt(2*pi) / sigma1(2,2) * exp(-(a2-mu1(2))^2/(2 * sigma1(2,2)^2));
% 计算 -1 类中 a1 a2 的概率
P(2,1) = 1 / sqrt(2*pi) / sigma2(1,1) * exp(-(a1-mu2(1))^2/(2 * sigma2(1,1)^2));
P(2,2) = 1 / sqrt(2*pi) / sigma2(2,2) * exp(-(a2-mu2(2))^2/(2 * sigma2(2,2)^2));
% 计算条件概率
p1 = P(1,1) * P(1,2) * p_count1 / (p_count1 + p_count2);
p2 = P(2,1) * P(2,2) * p_count2 / (p_count1 + p_count2);
% 根据概率大小判断分类
if p1 > p2
res(i) = 1;
else
res(i) = -1;
end
end
由于只有两类,所以分类也较为简单,不过更多类的情况也是类似的。
准确度
只介绍简单的分类准确度指标 accuracy ,定义为分类正确的样本数与总样本数之比。
% 计算准确度
acc = sum(res == target_con_gnd) / n;