Loading

朴素贝叶斯分类器

 

基本概念

朴素贝叶斯分类器计算一个样本属于某一类的概率(后验概率),进而比较概率大小来决定样本的分类结果。分类器需要数据集作为已知样本集,还需要这些样本的分类结果,最后对新给出的样本集进行分类。

具体来说,假设已经得到样本集 \(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(y_j|x) = \dfrac{\Pr(x|y_j)\Pr(y_j)}{\Pr(x)} \]

与先前类似,其中 \(\Pr(x)\) 可以忽略,我们用 \(D\) 中分类到 \(y_j\) 的元素占 \(D\) 所有元素的比例来估计 \(y_j\) 出现的概率 \(\Pr(y_j)\)

于是重点就在于计算 \(\Pr(x|y_j)\) ,我们知道 \(x\) 有一些特征,那么

\[\Pr(x|y_j) = \prod_{i=1}^k\Pr(a_i|y_j) \]

也就是 \(x\)每一个特征都出现\(y_j\) 中的概率,其中 \(\Pr(a_i|y_j)\)\(a_i\) 出现在 \(y_j\) 分类中的比例。最终就得到

\[\Pr(y_j|x) \varpropto \Pr(y_j)\prod_{i=1}^k\Pr(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];

因此需要计算每个分类中不同特征出现的概率

\[\begin{matrix} \Pr(a_1| y_1) & \Pr(a_2| y_1)\\ \Pr(a_1| y_2) & \Pr(a_2| y_2) \end{matrix} \]

用一个矩阵来存放上面的概率

% 记录概率 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;

然后计算出似然估计

\[\Pr(x|y_1) = \Pr(a_1| y_1) \Pr(a_2| y_1)\cdot \Pr(y_1)\\ \Pr(x|y_2) = \Pr(a_1| y_2) \Pr(a_2| y_2)\cdot \Pr(y_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);

比较两个概率的大小决定分到哪一类即可。

 

连续分类

对于连续数据,通常是将其转化为离散数据集,包括两种方法

  • 将特征取值范围分成几个较少的区间
  • 假设每个类别中样本特征服从不同期望方差下的正态分布

第一种方法下,直接使用上面的方案即可;如果是第二种方法,我们假定 \(y_j\) 类中出现的特征 \(a_i\) 服从正态分布

\[g(x,\mu,\sigma) = \dfrac{1}{\sqrt{2\pi}\sigma}\exp(-\frac{(x-\mu)^2}{2\sigma^2}) \]

这样就可令 \(\Pr(a_i|y_j) = g(a_i,\mu,\sigma)\) ,其中 \(\mu\)\(\sigma^2\)\(y_j\) 中出现的特征 \(a_i\) 的期望和方差。我们用平均值来近似期望,使用无偏方差

\[D(X) = \dfrac{1}{n-1}\sum_{i=1}^n(X_i-\overline{X})^2 \]

假定不同特征的协方差为 \(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;
posted @ 2022-03-15 22:30  Bluemultipl  阅读(568)  评论(0编辑  收藏  举报