机器学习之朴素贝叶斯分类器附C++代码

一、基本概念:

  • 先验概率(prior probability):是指根据以往经验和分析得到的概率,如全概率公式,它往往作为"由因求果"问题中的"因"出现的概率。比如,抛一枚硬币,正面朝上的概率P(A)=1/2,就是先验概率。
  • 联合概率:表示两个事件共同发生的概率。A与B的联合概率表示为 P(AB) 或者P(A,B),或者P(A∩B)。
  • 条件概率:已知事件A发生的条件下事件B发生概率,条件概率表示为P(B|A)
  • 后验概率:例如事件B1、B2、B3等都会导致事件A发生。现在事件A已经发生,求事件A发生是由B1、B2、B3那个事件引起的条件概率P(Bi|A),就是后验概率。举个在《概率论》中经常用到的例子,事件B1、B2、B3代表三个不同的工厂生产零件,事件A是生产次品的事件,P(A|Bi)是三个工厂的次品率。现在事件A发生了,判断是由那个工厂生产的这个次品P(Bi|A)

二、贝叶斯定理:

在现实生活中,我们可以很容易直接得出P(A|Bi),而P(Bi|A)则很难直接得出,但我们更关心P(Bi|A),贝叶斯定理实现了由P(A|Bi)计算P(Bi|A)的方法。

贝叶斯公式: 

          

贝叶斯算法的基础是概率推理,是在各种条件的存在不确定、仅知其出现的概率情况下,完成推理和决策任务。而朴素贝叶斯模型(Naive Bayesian Model)是基于独立假设的,即假设样本的每一个特征与其他特征都不相关。

三、贝叶斯分类器基本原理

此时贝叶斯公式写为:



训练:

1.  设样本集 ,其中。所有类别集合

2.  计算先验概率P(Ci)。

3.  计算类条件密度:

    



测试:

1.设为待分类项,而每个ai为X的一个特征属性

2.计算

3.根据贝叶斯定理求后验概率P(Ci|X),得到X属于Ci类别的后验概率;根据最大后验概率判断所属类别。

  P(C α |X)=max{P(Ci|X)} ,则测试样本属于Cα


四、举例说明

如图所示,为某电脑卖家统计的客户信息,有14个样本(X1,X2,...X14),其中每个样本有四个属性,{a1(age),a2(income),a3(student),a4(credit_rating)}。根据以上信息,如果再给出一个客户的这四种信息,如{(<30),medium,no,fair},判断他会不会买电脑。也是一个简单的二分类问题。

为了便于表示,把年龄<=30、31—40、>40用Tw(Twenty)、Th(Thirty)、F(Forty)来表示。


训练:

1. 设样本集 ,其中。所有类别集合

    

2.  计算先验概率P(C1)=5/14;P(C2)=9/14。

3.  计算类条件密度:

属性a1:P(TwC1)=3/14;P(ThC1)=0/14;P(FC1)=2/14;P(TwC2)=2/14;P(ThC2)=4/14;P(FC2)=3/14;

        P(Tw|C1)=3/5;P(Th|C1)=0/5;P(F|C1)=2/5;P(Tw|C2)=2/9;P(Th|C2)=4/9;P(F|C2)=3/9;

属性a2:P(HC1)=2/14;P(MC1)=2/14;P(LC1)=1/14;P(HC2)=2/14;P(MC2)=4/14;P(LC2)=3/14;

        P(H|C1)=2/5;P(M|C1)=2/5;P(L|C1)=1/5;P(H|C2)=2/9;P(M|C2)=4/9;P(L|C2)=3/9;

属性a3:P(NC1)=4/14;P(YC1)=1/14;P(NC2)=3/14;P(YC2)=6/14;

        P(N|C1)=4/5;P(Y|C1)=1/5;P(N|C2)=3/9;P(Y|C2)=6/9;

属性a4:P(FC1)=2/14;P(EC1)=3/14;P(FC2)=6/14;P(EC2)=3/14;

        P(F|C1)=2/5;P(E|C1)=3/5;P(F|C2)=6/9;P(E|C2)=3/9;

测试:

1.设X={(<30),medium,no,fair}为待分类项,

2.计算

P(X|C1)P(C1)=P(a1|C1)*P(a2|C1)*P(a3|C1)*P(a4|C1)P(C1)

            =P(Tw|C1)*P(M|C1)*P(N|C1)*P(F|C1)*P(C1)=(3/5)*(2/5)*(4/5)*(2/5)*(5/14)= 0.0274;

P(X|C2)P(C2)=P(a1|C2)*P(a2|C2)*P(a3|C2)*P(a4|C2)P(C2)

            =P(Tw|C2)*P(M|C2)*P(N|C2)*P(F|C2)*P(C2)=(2/9)*(4/9)*(3/9)*(6/9)*(9/14)= 0.0141;


3.根据贝叶斯定理求后验概率,得到X属于Ci类别的后验概率;根据最大后验概率判断所属类别。

  P(C α |X)=max{P(Ci|X)} ,则测试样本属于Cα

  P(X|C1)P(C1)>P(X|C2)P(C2)==>P(C1|X)>P(C2|X),

所以,此人不买电脑的概率大。

五、程序

1.这里只给出main函数部分,因为这个程序也是本人在网上下载别人的,可以验证,程序运行结果与计算结果相同

  地址:http://download.csdn.net/download/theone_jie/9464087

//朴素贝叶斯分类器程序
#include <cstdio>
#include <Windows.h>
#include "LBayesClassifier.h"

const int NUM =14;  //训练样本个数
const int Dim =4;   //训练样本的维数

int main()
{
    /*定义样本矩阵
    每一行代表一个样本
    第一列为age,第二列为income,第3列为student,第4列为credit_rating
    把个属性进行了数字化,(<=30:20)、(31-40:30)、(>40:40);
	(high:3)(medium:2)(low:1);(no:0)(yes:1);(fair:0)(excellent:1)
	*/
    int dataList[NUM*Dim] = 
	{   20,3,0,0,
		20,3,0,1,
		30,3,0,0,
		40,2,0,0,
		40,1,1,0,
		40,1,1,1,
		30,1,1,1,
		20,2,0,0,
		20,1,1,0,
		40,2,1,0,
		20,2,1,1,
		30,2,0,1,
		30,3,1,0,
		40,2,0,1}; 
    LBayesMatrix sampleMatrix(NUM, Dim, dataList);

    //定义样本的类别向量(0:不买电脑;1:买电脑)
    int classList[NUM] = {0,0,1,1,1,0,1,0,1,1,1,1,1,0};
    LBayesMatrix classVector(NUM, 1, classList);

    //定义贝叶斯原始问题
    LBayesProblem problem(sampleMatrix, classVector, BAYES_FEATURE_CONTINUS);

    //定义贝叶斯分类器, 并且训练
    LBayesClassifier classifier;
    classifier.TrainModel(problem);

    //输入新样本, 并预测新样本的类别
    LBayesMatrix newSample(1, Dim);
    newSample[0][0] = 20; 
	newSample[0][1] = 2; 
	newSample[0][2] = 0;
    newSample[0][3] = 0;
    int predictValue ; 
    classifier.Predict(newSample, &predictValue);

    printf("%d\n", predictValue);
    system("pause");
    return 0;
}


2.最后在附加了opencv自带的正态贝叶斯分类器

//opencv自带正态贝叶斯分类器(Normal Bayes Classifier)
#include "opencv2/ml/ml.hpp"

using namespace std;  
using namespace cv;  
const int NUM=14;   //训练样本的个数
const int D=4;     //维度
//14个维数为4的训练样本集
double inputArr[NUM][D] =   
					{  20,3,0,0,
					   20,3,0,1,
					   30,3,0,0,
					   40,2,0,0,
					   40,1,1,0,
					   40,1,1,1,
					   30,1,1,1,
					   20,2,0,0,
					   20,1,1,0,
					   40,2,1,0,
					   20,2,1,1,
					   30,2,0,1,
					   30,3,1,0,
					   40,2,0,1};  
  
//一个测试样本的特征向量  
double testArr[]={20,3,0,0};  
  
int main()  
{  
    Mat trainData(NUM, D, CV_32FC1);//构建训练样本的特征向量  
    for (int i=0; i<NUM; i++)  {  
        for (int j=0; j<D; j++)  {  
            trainData.at<float>(i, j) = inputArr[i][j+1];  
        }  
    }  
    Mat trainResponse=(Mat_<float>(NUM,1)<<
		0,0,1,1,1,0,1,0,1,1,1,1,1,0);//构建训练样本的类别标签  
   
    CvNormalBayesClassifier Mybayes;  
    bool trainFlag = Mybayes.train(trainData, trainResponse);//进行贝叶斯分类器训练  
    if (trainFlag)  {  
        cout<<"train over..."<<endl;  
        Mybayes.save("normalBayes.txt");  
    }  
    else  {  
        cout<<"train error..."<<endl;  
        system("pause");  
        exit(-1);  
    }  
    CvNormalBayesClassifier Tbayes;  
    Tbayes.load("normalBayes.txt");  
  
    Mat testSample(1, D, CV_32FC1);//构建测试样本  
    for (int i=0; i<D; i++)  {  
        testSample.at<float>(0, i) = testArr[i];  
    }    
    float flag = Tbayes.predict(testSample);//进行测试  
    cout<<"flag = "<<flag<<endl;  
    system("pause");  
    return 0;  
}
本人能力有限,难免有出错的地方。敬请赐教

更多资源:http://blog.csdn.net/lavorange/article/details/17841383
  • 4
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
以下是朴素贝叶斯分类器的伪代码: 1. 训练阶段: (1)对于每个类别 i,计算先验概率P(Y=i)。 (2)对于每个特征 j,计算在每个类别 i 下该特征的条件概率P(Xj=x|Y=i)。 2. 测试阶段: (1)对于输入样本 x,计算该样本属于每个类别 i 的条件概率P(Y=i|X=x)。 (2)将样本分到概率最大的类别中。 下面是朴素贝叶斯分类器C++ 代码实现,其中假设特征和类别都是离散的: ``` #include <iostream> #include <vector> #include <map> #include <cmath> using namespace std; // 计算先验概率 map<int, double> cal_prior_prob(vector<int>& labels) { map<int, double> prior_prob; int total = labels.size(); for (int i = 0; i < total; i++) { int label = labels[i]; if (prior_prob.find(label) == prior_prob.end()) { prior_prob[label] = 0.0; } prior_prob[label] += 1.0; } for (auto iter = prior_prob.begin(); iter != prior_prob.end(); iter++) { iter->second /= total; } return prior_prob; } // 计算条件概率 map<int, map<int, double>> cal_cond_prob(vector<vector<int>>& features, vector<int>& labels) { map<int, map<int, double>> cond_prob; int total = labels.size(); int feature_num = features[0].size(); for (int i = 0; i < total; i++) { int label = labels[i]; if (cond_prob.find(label) == cond_prob.end()) { cond_prob[label] = map<int, double>(); } for (int j = 0; j < feature_num; j++) { int feature = features[i][j]; if (cond_prob[label].find(j) == cond_prob[label].end()) { cond_prob[label][j] = map<int, double>(); } if (cond_prob[label][j].find(feature) == cond_prob[label][j].end()) { cond_prob[label][j][feature] = 0.0; } cond_prob[label][j][feature] += 1.0; } } for (auto iter1 = cond_prob.begin(); iter1 != cond_prob.end(); iter1++) { int label = iter1->first; for (auto iter2 = iter1->second.begin(); iter2 != iter1->second.end(); iter2++) { int feature = iter2->first; int feature_total = iter2->second.size(); for (auto iter3 = iter2->second.begin(); iter3 != iter2->second.end(); iter3++) { iter3->second /= feature_total; } } } return cond_prob; } // 预测 int predict(vector<int>& feature, map<int, double>& prior_prob, map<int, map<int, double>>& cond_prob) { int label = -1; double max_prob = -1.0; for (auto iter = prior_prob.begin(); iter != prior_prob.end(); iter++) { int cur_label = iter->first; double cur_prob = log(iter->second); for (int i = 0; i < feature.size(); i++) { cur_prob += log(cond_prob[cur_label][i][feature[i]]); } if (cur_prob > max_prob) { max_prob = cur_prob; label = cur_label; } } return label; } // 测试 void test(vector<vector<int>>& features, vector<int>& labels, map<int, double>& prior_prob, map<int, map<int, double>>& cond_prob) { int total = labels.size(); int correct = 0; for (int i = 0; i < total; i++) { int predict_label = predict(features[i], prior_prob, cond_prob); if (predict_label == labels[i]) { correct++; } } cout << "Accuracy: " << (double)correct / total << endl; } int main() { // 读取数据,features存放特征,labels存放类别 vector<vector<int>> features; vector<int> labels; // 训练 map<int, double> prior_prob = cal_prior_prob(labels); map<int, map<int, double>> cond_prob = cal_cond_prob(features, labels); // 测试 test(features, labels, prior_prob, cond_prob); return 0; } ``` 注意:这里的代码只是朴素贝叶斯分类器的一种实现方式,可能还有其他实现方式。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值