基于C++的朴素贝叶斯分类器

Posted Kalzn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于C++的朴素贝叶斯分类器相关的知识,希望对你有一定的参考价值。

基于C++的朴素贝叶斯分类器

github链接
使用c++编写的朴素贝叶斯分类器,其中似然中的离散分量,以及先验概率使用拉普拉斯平滑,连续分量为正态分布。

警告,此代码仅为初学学习之用,请勿用作任何工程项目!

一、跑起来

方式一

使用vscode+cmake插件或者Clion打开目录。然后直接编译运行。

方式二

1、确保安装cmake环境,没有请先装cmake。
2、在工程目录下键入:

mkdir build
cd build
cmake ..
make

3、运行build目录下的程序Bayers_classifier程序

二、用起来

1、建立模型

Simple_Bayes_Classifier::Info info;
/**
    struct Info 
        int sample_num; // 样例数量
        std::vector<int> header; // 样例格式,
                                 // 如当前分量为离散值则为样例可能取值的数量,
                                 // 如为连续值则填0,
                                 // 例如,现有样例格式为这样 :
                                 //           x0 属于 "东","南","西","北"
                                 //           x1 属于 "左","右"
                                 //           x2 属于 x|0<x<100 为连续值
                                 // 则 header=4, 2, 0
                                                           
        int class_num; // 分类数量
        int sample_size; // 样例分量维度大小
     
 */
Simple_Bayes_Classifier model(info);

2、读取文件,训练模型

model.train("data/1.txt"); // 文件格式为:每行一个样例,每个样例n个分量用空格隔开,最后为该样例所属分类

示例文件格式:

3、开始分类, 构造出一个待分类的样例,然后分类结果赋值到样例的belong_to字段

Sample s;
s.add_parameter(x); s.add_parameter(y);
model.classify(s);
std::cout << s.belong_to << std::endl;

三、学起来

贝叶斯分类器的基石为Bayes公式:

P ( A i ∣ B ) = P ( B ∣ A i ) P ( A i ) ∑ j = 1 n P ( B ∣ A j ) P ( A j ) P(A_i|B)=\\fracP(B|A_i)P(A_i)\\sum_j=1^nP(B|A_j)P(A_j) P(AiB)=j=1nP(BAj)P(Aj)P(BAi)P(Ai)

若现在存在样例的向量为 x \\boldsymbolx x,而其所属分类为 c c c的概率为:

P ( c ∣ x ) = p ( c ) p ( x ∣ c ) p ( x ) P(c|\\boldsymbolx)=\\fracp(c)p(\\boldsymbolx|c)p(\\boldsymbolx) P(cx)=p(x)p(c)p(xc)

其中,我们把 p ( c ) p(c) p(c)称为先验概率(prior),而 p ( x ∣ c ) p(\\boldsymbolx|c) p(xc)则为似然(likelihood)而 p ( x ) p(\\boldsymbolx) p(x)称为证据(evidence)。当分类器工作时,遵循 h ( x ) h(\\boldsymbolx) h(x),我们需要比较 n n n种分类,选择概率最大的分类。
h ( x ) = a r g m a x c ∈ Y P ( c ∣ x ) h(\\boldsymbolx)=argmax_c\\in YP(c|\\boldsymbolx) h(x)=argmaxcYP(cx)

P ( c ∣ x ) ∝ p ( c ) p ( x ∣ c ) P(c|\\boldsymbolx) \\propto p(c)p(\\boldsymbolx|c) P(cx)p(c)p(xc)

所以我们可以忽略证据,针对每个待分类的样例,对每种分类计算先验概率和似然即可。

先验概率 p ( c ) p(c) p(c)一般直接进行数量统计,即:
p ( c ) = ∣ D c ∣ ∣ D ∣ p(c)=\\frac|D_c||D| p(c)=DDc

其中 D c D_c Dc为训练集中。所属类别 c c c的样例集,而 ∣ D ∣ |D| D为全体训练集。

而计算较为困难的是似然 p ( x ∣ c ) p(\\boldsymbolx|c) p(xc),在朴素贝叶斯中,我们认为向量 x \\boldsymbolx x的所有分量的取值是独立的,此时有:
p ( x ∣ c ) = ∏ i = 0 n p ( x i ∣ c ) p(\\boldsymbolx|c)=\\prod_i=0^np(x_i|c) p(xc)=i=0np(xic)

此时即可进行运算,这里如果 x i x_i xi为离散值,则可以直接进行统计:

p ( x i ∣ c ) = ∣ D i , c ∣ ∣ D c ∣ p(x_i|c)=\\frac|D_i,c||D_c| p(xic)=DcDi,c

其中 D i , c D_i,c Di,c是训练集中满足:所属类别为 c c c i i i分量为 x i x_i xi的集合。

而如果 x i x_i xi为连续值,则这里可以将其看成正态分布:

p ( x i ∣ c ) = 1 2 π σ i , c e − ( x i − μ i , c ) 2 2 σ i , c 2 p(x_i|c)=\\frac1\\sqrt2\\pi\\sigma_i,ce^-\\frac(x_i-\\mu_i,c )^22\\sigma_i,c^2 p(xic)=2π σi,c1e2σi,c2(xiμi,c)2

其中 σ i , c 2 , μ i , c \\sigma_i,c^2,\\mu_i,c σi,c2,μi,c分别为所属类别为 c c c的训练集的 i i i分量的方差和均值。

至此我们解决了朴素贝叶斯分类器。

在有些时候,向量 x \\boldsymbolx x的分量不是独立的,一种常见的情况是所有分量满足多维正态分布 N ( μ , Σ ) N(\\mu, \\Sigma) N(μ,Σ)。为了清晰设置 e x p ( x ) = e x exp(x)=e^x exp(x)=ex

p ( x ) = 1 ( 2 π ) d 2 ∣ Σ ∣ 1 2 e x p ( − 1 2 ( x − μ ) T Σ − 1 ( x − μ ) ) p(\\boldsymbolx)=\\frac1(2\\pi)^\\fracd2|\\Sigma|^\\frac12exp\\left ( -\\frac12 (\\boldsymbolx-\\boldsymbol\\mu )^T\\Sigma^-1(\\boldsymbolx-\\boldsymbol\\mu ) \\right ) p(x)=(2π)2d∣Σ211exp(−以上是关于基于C++的朴素贝叶斯分类器的主要内容,如果未能解决你的问题,请参考以下文章

基于C++的朴素贝叶斯分类器

基于朴素贝叶斯分类器的情感分析

机器学习——朴素贝叶斯算法

用于朴素贝叶斯分类器的伯努利模型的拉普拉斯平滑

机器学习笔记——朴素贝叶斯构建“饥饿站台”豆瓣短评情感分类器

从朴素贝叶斯分类到贝叶斯网络