朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。对于搞机器学习的同学们来说,这是相对简单但效果较好的模型。

朴素贝叶斯方法的理论

设输入为n维特征向量X={x1,x2,...,xn},输出为类标记集合Y={c1,c2,...ck}。朴素贝叶斯法通过训练数据集学习联合概率分布P(X,Y),其中X是n维,Y是分类标记。有了模型P(X,Y),要预测一个特征向量的分类标记,则分别计算P(X,Y=c1),P(X,Y=c2),...P(X,Y=ck),选择取最大值的p(X,Y=cm),将cm作为X的分类标记。但对于模型P(X,Y)中的X是n维随机变量,若每一维特征取值最少有两个值,那么模型P(X,Y)参数量将是指数级的,这在特征维度较大的时候是不可行的。朴素贝叶斯法是引入条件独立性假设,由条件概率可得:

            P(X=x,Y=ck)

            =P(X(1)=x(1),X(2)=x(2),...X(n)=x(n)|Y=ck)*P(Y=ck)

 (应用条件独立性假设)=P(X(1)=x(1)|Y=ck)*P(X(2)=x(2)|Y=ck)*...*P(X(n)=x(n)|Y=ck)*P(Y=ck)

          即   =P(Y=ck)*∏i=1..nP(X(i)=x(i)|Y=ck)

条件独立性假设等于说用于分类的特征在类确定的情况下都是条件独立的。通过条件独立性假设,朴素贝叶斯法是模型变得简单,参数数量大大减少,但也牺牲一定的分类准确率。

朴素贝叶斯参数估计-极大似然估计

计算先验概率P(Y=ck)

P(Y=ck)=(∑i=1..nI(yi=ck))/N   , k=1,2,...,K

其中I(yi=ck)为指示函数,当yi=ck时函数值等于1,否则为0。

计算条件概率P(X(j)=ajl|Y=ck)

P(X(j)=ajl|Y=ck)=(∑i=1..nI(xi(j)=ajl,yi=ck))/∑i=1..nI(yi=ck)   ,j=1,2,,,n; l=1,2,S;k=1,2,K

其中Sj是第j维特征的取值数。

由于计算条件概率可能会造成某个特征的计数为零,这样在预测分类的时候就会对有该特征的类计算值为0.为了避免这种情况,可采用拉普拉斯平滑处理。

预测分类

对给定的实例x=(x(1),x(2),...x(n))T,计算

P(Y=ck)*∏i=1..nP(X(i)=x(i)|Y=ck), k=1,2,...,K

然后根据上述K个结果,确定x的分类

y=argmax P(Y=ck)*∏i=1..n P(X(i)=x(i)|Y=ck)

例:

训练数据

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
x(1) 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
x(2) S M M S S S M M L L L M M L L
Y -1 -1 1 1 -1 -1 -1 1 1 1 1 1 1 1 -1

数据存储在文件中,每一行存储格式为<x(1) x(2) Y>,即特征1,特征2,分类属性以空格分隔。如下

1 S -1
1 M -1
1 M  1
1 S  1
1 S -1
2 S -1
2 M -1
2 M  1
2 L  1
2 L  1
3 L  1
3 M 1
3 M 1
3 L  1
3 L -1

代码如下:

/********************************************************************/
/*
朴素贝叶斯法
*/
/************************************************************************/
#include<iostream>
#include<string>
#include<fstream>
#include<sstream>
#include<vector>
#include<map>
#include<set>
using namespace std;
class naiveBayes{
public:
     //载入数据并统计分量计数  
void loadData(){
ifstream fin(dataFile.c_str());
if(!fin){
cout<<"数据文件打开失败"<<endl;
exit(0);
}
while(fin){
string line;
getline(fin,line);
if(line.size()>1){
stringstream sin(line);
string s[2];
int c;
sin>>s[0]>>s[1]>>c;
//cout<<s1<<" "<<s2<<" "<<c<<endl;
dataSize++;
if(ym.count(c)>0){
ym[c]++;
}else{
ym[c]=1;
}
for(int i=0;i<2;i++){
if(feam.count(s[i])>0){
if(feam[s[i]].count(c)>0){
feam[s[i]][c]++;
}else{
feam[s[i]][c]=1;
}
}else{
map<int,int> mt;
mt[c]=1;
feam[s[i]]=mt;
}
}
} } }
     //显示map模型
void dispModel(){
cout<<"训练数据总数"<<endl;
cout<<dataSize<<endl;
cout<<"分类统计计数"<<endl;
for(map<int,int>::iterator mi=ym.begin();mi!=ym.end();mi++){
cout<<mi->first<<" "<<mi->second<<endl;
}
cout<<"特征统计计数:"<<endl;
for(map<string, map<int,int> >::iterator mi=feam.begin();mi!=feam.end();mi++){
cout<<mi->first<<": ";
for(map<int,int>::iterator ii=mi->second.begin();ii!=mi->second.end();ii++){
cout<<"<"<<ii->first<<" "<<ii->second<<"> ";
}
cout<<endl;
}
}
     //预测分类
void predictive(){
string x1,x2;
cout<<"请输入测试数据(包括两维特征,第一维取值<1,2,3>;第二维取值<S,M,L>)"<<endl;
string a1[]={"1","2","3"};
string a2[]={"M","S","L"};
set<string> a1set(a1,a1+3);
set<string> a2set(a2,a2+3);
while(cin>>x1>>x2){
if(a1set.count(x1)>0&&a2set.count(x2)>0){
double py1=(double(ym[-1])/dataSize)*(double(feam[x1][-1])/ym[-1])*(double(feam[x2][-1])/ym[-1]);
double py2=(double(ym[1])/dataSize)*(double(feam[x1][1])/ym[1])*(double(feam[x2][1])/ym[1]);
cout<<"y=-1的得分为"<<py1<<endl;
cout<<"y=1的得分为"<<py2<<endl;
cout<<"<"<<x1<<","<<x2<<">"<<"所属分类为:";
if(py1>py2){
cout<<"-1";
}else{
cout<<"1";
}
cout<<endl;
cout<<endl;
cout<<"继续测试(ctrl+Z结束)"<<endl;
}else{
cout<<"输入特征为:第一维取值<1,2,3>;第二维取值<S,M,L>,空格分隔。输入有误,请重新输入"<<endl;
}
}
}
naiveBayes(string df="data.txt"):dataFile(df),dataSize(0){
}
private:
string dataFile;
int dataSize;
//分类->计数
map<int,int> ym;
//分类->( 特征->计数 )
map<string, map<int,int> >feam;
};
int main(){
naiveBayes nb;
nb.loadData();
nb.dispModel();
nb.predictive();
system("pause");
return 0;
}

程序运行结果:

本例中,参数估计采用的是贝叶斯估计,有时间再把拉普拉斯平滑加上。

朴素贝页斯分类法 c++实现的更多相关文章

  1. 亚马逊CEO贝索斯致股东信:阐述公司未来计划

    亚马逊CEO 杰夫·贝索斯(Jeff Bezos)今天发布年度股东信, 详细描述了亚马逊的产品.服务和未来计划,当然,信中并没有任何的硬数据,比如说亚马逊Kindle的销量等等.但这封信也包括一些颇令 ...

  2. ios项目里扒出来的json文件

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Menlo; color: #000000 } p.p2 { margin: 0.0px 0. ...

  3. Github上关于iOS的各种开源项目集合(强烈建议大家收藏,查看,总有一款你需要)

    下拉刷新 EGOTableViewPullRefresh - 最早的下拉刷新控件. SVPullToRefresh - 下拉刷新控件. MJRefresh - 仅需一行代码就可以为UITableVie ...

  4. iOS及Mac开源项目和学习资料【超级全面】

    UI 下拉刷新 EGOTableViewPullRefresh – 最早的下拉刷新控件. SVPullToRefresh – 下拉刷新控件. MJRefresh – 仅需一行代码就可以为UITable ...

  5. iOS:iOS开发非常全的三方库、插件等等

    iOS开发非常全的三方库.插件等等 github排名:https://github.com/trending, github搜索:https://github.com/search. 此文章转自git ...

  6. iOS开发--iOS及Mac开源项目和学习资料

    文/零距离仰望星空(简书作者)原文链接:http://www.jianshu.com/p/f6cdbc8192ba著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 原文出处:codecl ...

  7. iOS、mac开源项目及库汇总

    原文地址:http://blog.csdn.net/qq_26359763/article/details/51076499    iOS每日一记------------之 中级完美大整理 iOS.m ...

  8. iOS、mac开源项目及库(感谢原作者的分享)

    目录 模糊效果 富文本 表相关 HUD与Toast 其他UI 其他动画 网络测试 网络聊天 Model 数据库 PDF 摄像照相视频音频处理 消息相关 消息推送服务器端 版本新API的Demo 测试及 ...

  9. iOS超全开源框架、项目和学习资料汇总--数据库、缓存处理、图像浏览、摄像照相视频音频篇

    iOS超全开源框架.项目和学习资料汇总--数据库.缓存处理.图像浏览.摄像照相视频音频篇 感谢:Ming_en_long 的分享 大神超赞的集合,http://www.jianshu.com/p/f3 ...

随机推荐

  1. 【C++】智能指针auto_ptr简单的实现

    //[C++]智能指针auto_ptr简单的实现 #include <iostream> using namespace std; template <class _Ty> c ...

  2. HDOJ 3037 Saving Beans

    如果您有n+1树,文章n+1埋不足一棵树m种子,法国隔C[n+m][m] 大量的组合,以取mod使用Lucas定理: Lucas(n,m,p) = C[n%p][m%p] × Lucas(n/p,m/ ...

  3. 假设动态运行java文字,当在脚本式配置,这是非常方便的

    package com.bfrj.core.groovy; import java.util.HashMap; import java.util.Map; import org.jeecgframew ...

  4. SQL中条件放在on后与where后的区别

    SQL中on条件与where条件的区别 数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion时,on和where条件的区别如下: ...

  5. POJ 1664 把苹果

     把苹果 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 25785   Accepted: 16403 Descript ...

  6. linux_安装_安装编译phantomjs 2.0的方法_转

    项目中要对数据公式webkit渲染,phantmjs 2.0的效果好比1.9好不少. 安装过程中 坑比较多. 转载文章: phantomjs 2.0最新版的官方不提供编译好的文件下载,只能自己编译,有 ...

  7. crawler_httpclient代理访问

    public String getDocumentByProxy(String url) throws ClientProtocolException, IOException { DefaultHt ...

  8. 从头开始学JavaScript (五)——操作符(二)

    原文:从头开始学JavaScript (五)--操作符(二) 一.乘性操作符 1.乘法:*      乘法操作符的一些特殊规则: 如果操作数都是数值,按照常规的乘法计算,如果乘积超过了ECMAscri ...

  9. Android Application.java以及它的作用

    What is Application Application和Activity,Service一样是android框架的一个系统组件,当android程序启动时系统会创建一个 application ...

  10. Android结构分析Android智能指针(两)

    笔者:刘蒿羽 博客:http://blog.csdn.net/liuhaoyutz Android版本号:4.4.2 在上一篇文章中,我们分析了Android智能指针中的强指针sp,本文我们来分析弱指 ...