根据贝叶斯定理,对一个分类问题,给定样本特征x,样本属于类别y的概率是

在这里,x是一个特征向量,将设x维度为M。因为朴素的假设,即特征条件独立,根据全概率公式展开,上述公式可以表达为

这里,只要分别估计出,特征xi在每一类的条件概率就可以了。类别y的先验概率可以通过训练集算出,同样通过训练集上的统计,可以得出对应每一类上的,条件独立的特征对应的条件概率向量。

以下结合代码谈谈具体的实现

struct questionnaire{char x[4];int y[24];char x3;char x5;int y6[6];char x7;
};

首先定义一个questionnaire的结构体

x[0]~x[3]分别表示基本信息中的性别、年龄、学业背景和职业

需要说明的是,我们把多选题看做n道单选题,这每道单选题的答案集合只有yes和no

y[0]~y[4]位主题问卷第一题的abcde

y[5]~y[10]位主题问卷第二题的abcdef

y[11]为第四题

y[12]~y[17]为第八题的abcdef

y[18]~y[23]为第八题的abcdeg

x3为第三题

x5为第五题

y6[0]~y6[5]为第六题的abcdef

x7为第七题

关于我们类的设置,先来看看我们的总体思路:

第一步先是学习的过程,也就是结合问卷统计相关的数量来计算我们所需要的概率为后面一步利用贝叶斯公式来计算(分类)打下基础。

如果说我们的训练集是TrainingSet={(x1,y1),(x2,y2),...,(xN,yN)} 包含N条训练数据,其中 xi=(x(1)i,x(2)i,...,x(M)i)T是M维向量,yi∈{c1,c2,...cK}属于K类中的一类。

学习 1.首先,我们来计算上面公式中的p(y=ck)

其中I(x)为指示函数,若括号内成立,则计1,否则为0。

学习 2.接下来计算分子中的条件概率,设M维特征的第j维有L个取值,则某维特征的某个取值ajl,在给定某分类ck下的条件概率为:

为了避免出现统计量为零时概率算出也为零的不符合实际的情况,根据拉普拉斯平滑改进这两个式子,改进完上述式子变为:

K是类的个数

Lj是第j维特征的最大取值,λ是一个常数,我们将其设置为1就好。

这就是我们第一步的学习步骤,所以结合代码看看我们的类是怎么设计的。

class allQuestionnaires{
public:questionnaire sample[N];double p_yck[24][2];double p_when_yck_then_x[24][2][22];double p_yck3[4];double p_when_yck3_then_x[4][22];double p_yck6[6][2];double p_when_yck6_then_x[6][2][22];double p_yck5[3];double p_when_yck5_then_x[3][22];double p_yck7[5];double p_when_yck7_then_x[5][22];
};

这是我们的allQuestionnaires类的成员变量,为了方便将所有的变量都设为public的访问权限。首先定义一个questionnaire的数组,其中N是一个全局变量,代表问卷的总数。之后的p_yck就是p(y=ck),第一维的数字代表不同的问题,第二维的数字代表本题不同的选项,比如p_yck[24][2]的24代表的是第1289题的24个问题,2代表yes和no,所以这些变量所代表的含义为:

p_yck[0~4][0]为第一题五道单选题选yes的概率

p_yck[5~10][0]为第二题六道单选题选yes的概率

p_yck[11][0]为第四题选题选“体验过”的概率

p_yck[12~17][0]为第八题六道单选题选yes的概率

p_yck[18~23][0]为第九题六道单选题选yes的概率

选no的同理,将第二维改为1即可。所以p_yck3[4]、p_yck6[6][2]、p_yck5[3]、p_yck7[5]也就是第3657道题对应的解释,在此不做赘述。

而p_when_yck_then_x就是p(xj=ajl|y=ck),以p_when_yck_then_x[24][2][22]举例,第一维还是对应的1289的那24道题,第二维还是yes和no,而第三维表示的是基本信息里对应的22个选项,即0和1是“男”和“女”,2~7分别是年龄对应的六个选项,8~12为学历对应的五个选项,13~21为职业对应的九个选项。所以p_yck[0][0][0]的含义为第一题第一道小题选yes的情况下答题者性别为男的概率,其他的与此类似,不做赘述。

allQuestionnaires();~allQuestionnaires();void learn();void classify(char,char,char,char);void learn_classify_67(char,char,char,char);void learn_classify_5(char,char,char,char);

再来看看几个函数,第一个是构造函数,里面将包含初始化变量和读取文件的任务;第二个析构函数负责程序结束后的扫尾工作,第三个学习函数就是上文所说的两步学习的具体实现,第四个分类函数则会在下文给出原理。需要说明的是由于第5和67题和第四题的选择有关,所以把他们单独分离出来。

我们把问卷存在txt文档里存成下列形式,以其中两行做一个例子说明,一行代表一份问卷,它们分别对应的就是对应各个问题的选择,abcd的是单选题的选择,12的是多选题对应的小题的选择,1代表yes,2代表no,其中最后8个选择为5、6、7的选择,空是代表这个人第四题选了“去过“或”没去过”所以对应可以跳过相应的问题没有回答。

a b d g 2 1 1 2 2 2 1 2 2 1 2 b 2 1 2 2 2 22 1 2 1 1 2 1 a

a b d i 1 1 1 1 2 2 2 1 1 1 2 a 1 2 2 2 1 21 1 1 2 1 1 2   2 2 1 2 2 2 b

所以构造函数就不多说了,实现的效果就是把变量中p(y=ck)和p(xj=ajl|y=ck)先初始化为0,然后把txt里对应题目的对应答案读入到我们设置的结构体中去,即把所有sample的x[4]、y[24]、x3、x5、y6[6]、x7全都填满。

析构函数无需赘述,我们来看学习函数的具体实现。还是以其中的p_yck[24][2]和p_when_yck_then_x[24][2][22]为例子:

int help_p_yck[24];for(int i=0;i<24;i++)help_p_yck[i]=0;for(int i=0;i<N;i++)for(int j=0;j<24;j++)if(sample[i].y[j]==1)help_p_yck[j]++;for(int i=0;i<24;i++){p_yck[i][0]=double(help_p_yck[i]+1)/double(N+2);p_yck[i][1]=double(N-help_p_yck[i]+1)/double(N+2);}

第一步学习,通过统计每道题中某个选项出现的次数,再将其除以总数来求得每道题的每个选项的p(y=ck),记住应用拉普拉斯平滑。

int help_p_when_yck_then_x[24][2][22];for(intx=0;x<24;x++)for(inty=0;y<2;y++)for(int z=0;z<22;z++)help_p_when_yck_then_x[x][y][z]=0;for(intx=0;x<24;x++){for(inti=0;i<N;i++){for(intj=0;j<22;j++){intm2;if(sample[i].y[x]==1)m2=0;elsem2=1;switch(sample[i].x[0]){case'a':help_p_when_yck_then_x[x][m2][0]++;break;case'b':help_p_when_yck_then_x[x][m2][1]++;break;}//第一维}}

第二步学习,首先统计当某道题选择某个选项的情况下,基本信息四题的选择情况

for(int m=0;m<2;m++){p_when_yck_then_x[x][0][m]=double(help_p_when_yck_then_x[x][0][m]+1)/double(help_p_yck[x]+2);p_when_yck_then_x[x][1][m]=double(help_p_when_yck_then_x[x][1][m]+1)/double(N-help_p_yck[x]+2);}

接着再将取得的值除以第一步学习中已经求得相应的各题各选项的统计总数,来求得p(xj=ajl|y=ck),即当此题选此选项时,四个基本信息的选择频率计算得到。

由此,我们完成了学习部分,对于分类部分,先来看一下思路。

通过学到的概率,给定未分类新实例X,就可以通过上述概率进行计算,得到该实例属于各类的后验概率p(y=ck|X),因为对所有的类来说,第二个公式中分母的值都相同,所以只计算分子部分即可,具体步骤如下:

分类 1.计算该实例属于y=ck类的概率

分类 2.确定该实例所属的分类y

这个式子表示使某道题使分类1中那个式子得到的概率最大的那个选项作为我们的预测结果。于是我们得到了新实例的分类结果。

代码实现也十分清晰明了,以第一大题为例:

ofstream out("predict.txt");double P[4];for(intx=0;x<5;x++){out<<"第一题第"<<x+1<<"小题的预测结果是";P[0]=p_yck[x][0]*p_when_yck_then_x[x][0][sex-'a']*p_when_yck_then_x[x][0][2+age-'a']*p_when_yck_then_x[x][0][8+educatedbackground-'a']*p_when_yck_then_x[x][0][13+job-'a'];P[1]=p_yck[x][1]*p_when_yck_then_x[x][1][sex-'a']*p_when_yck_then_x[x][1][2+age-'a']*p_when_yck_then_x[x][1][8+educatedbackground-'a']*p_when_yck_then_x[x][1][13+job-'a'];if(P[0]>P[1]){out<<"yes"<<endl;}elseif(P[0]<P[1]){out<<"no"<<endl;}else{cout<<"第一题第"<<x+1<<"小题无法预测,yes no皆可以"<<endl;}}

打开要写入的txt文本,按照分类1的公式和学习步骤已经计算出的相关结果计算出p(y=ck|X),再比较相同一体内各个题目概率大小,输出预测结果。

至此,我们完成了所有的内容。运行代码,输入参数a b d g(代表 男 21~30 大学本科 学生),得到整份问卷的预测结果:

第一题第1小题的预测结果是yes

第一题第2小题的预测结果是yes

第一题第3小题的预测结果是yes

第一题第4小题的预测结果是yes

第一题第5小题的预测结果是no

第二题第1小题的预测结果是no

第二题第2小题的预测结果是no

第二题第3小题的预测结果是yes

第二题第4小题的预测结果是no

第二题第5小题的预测结果是no

第二题第6小题的预测结果是yes

第三题的预测结果是a

第四题的预测结果是没去过

第五题的预测结果是a

跳过第六七题

第八题第1小题的预测结果是no

第八题第2小题的预测结果是no

第八题第3小题的预测结果是no

第八题第4小题的预测结果是yes

第八题第5小题的预测结果是yes

第八题第6小题的预测结果是yes

第九题第1小题的预测结果是yes

第九题第2小题的预测结果是yes

第九题第3小题的预测结果是yes

第九题第4小题的预测结果是yes

第九题第5小题的预测结果是no

第九题第6小题的预测结果是no

可以看到,在这份问卷上的与用spss的统计分析完得到的结果还是比较吻合的,比如机器预测第三题这个人会选择“很有必要”,第四题会选“没去过”,第五题会是“根本没有时间”。

然而经过与随机抽出的20份问卷进行真实性对比,发现正确率并不是特别高,经过反思,我觉得原因如下:

1. 样本因素,学习算法最重要的还是靠丰富的样本量,对于我们的问卷情况,有一些实际情况导致预测结果正确率低,它们是:

(1)  问卷总数不够多

(2)  问卷上基本信息的各个选项不够丰满,比如选择小学、五六十岁、退休的人特别少,这造成当正好预测到这些人时预测效果十分离谱。

(3)  预测表现不好的那些题往往是几个选项概率比较接近的那些题,这个很好理解。所以表现出像第二题,这种选择比较分散的问题,预测结果就不好。

2. 模型因素,我们可以发现,对于单项题的预测正确率还可以,但是对于多选题就表现的不太好了,原因自然是我们把多选变单选这个做法上的不足,很容易造成的后果是某道多选题全yes或者全no(比如第二题),这自然没考虑到多选与同样数量的几道yes no的单选上的差异。

总体来说,作为用比较简单的机器学习模型——朴素贝叶斯公式作为对问卷最终数据分析预测的一种尝试,效果虽然不是特别好,但是如果在样本更加理想的情况下,预测效果还是可期的。虽然朴素贝叶斯要求的前提是“朴素”,即各道题间相互独立,但是经过千万人的经验,它在非独立但假设它独立的“朴素”前提下在分类领域依旧有很好的表现。而且因为其有对应的概率学上的公式可以推导,所以在对待问卷分析上还有便于预测后依据概率学公式进行分析这一优点。所以这一尝试还是十分成功的。

使用朴素贝叶斯进行问卷分析(C++)相关推荐

  1. 基于snownlp及朴素贝叶斯的情感分析——以大众点评网评论为例

    「情感分析」是对带有感情色彩的主观性文本进行分析.处理.归纳和推理的过程.按照处理文本的类别不同,可分为基于新闻评论的情感分析和基于产品评论的情感分析.其中,前者多用于舆情监控和信息预测,后者可帮助用 ...

  2. 详解基于朴素贝叶斯的情感分析及 Python 实现

    相对于「 基于词典的分析 」,「 基于机器学习 」的就不需要大量标注的词典,但是需要大量标记的数据,比如: 还是下面这句话,如果它的标签是: 服务质量 - 中 (共有三个级别,好.中.差) ╮(╯-╰ ...

  3. 朴素贝叶斯情感分析评分python_详解基于朴素贝叶斯的情感分析及 Python 实现

    相对于「 基于词典的分析 」,「 基于机器学习 」的就不需要大量标注的词典,但是需要大量标记的数据,比如: 还是下面这句话,如果它的标签是: 服务质量 - 中 (共有三个级别,好.中.差) �r(�s ...

  4. 朴素贝叶斯算法推导分析

    Author: DivinerShi 朴树贝叶斯方法其实就是一个根据先验求后验的过程. **优点:**思想简单,实现方便,适合小规模数据,适合多分类问题: **缺点:**需要基于一定的假设,假设各个特 ...

  5. 朴素贝叶斯情感分析评分python_详解基于朴素贝叶斯的情感分析及Python实现

    朴素贝叶斯 1.贝叶斯定理 假设对于某个数据集,随机变量C表示样本为C类的概率,F1表示测试样本某特征出现的概率,套用基本贝叶斯公式,则如下所示: 上式表示对于某个样本,特征F1出现时,该样本被分为C ...

  6. 机器学习之朴素贝叶斯二、情感分析实践

    目录标题 一.什么是朴素贝叶斯? 二.利用朴素贝叶斯进行情感分析 1. 数据类别说明 2. 什么是词袋模型 3. 数据展示 4. 利用词袋模型进行词表构建 5. 到了这一步,我们的前期工作都已经准备好 ...

  7. 【机器学习】朴素贝叶斯、SVM和数据分布检验分析

    [机器学习]朴素贝叶斯.SVM和数据分布检验分析 文章目录 1 朴素贝叶斯 2 SVM2.1 线性可分2.2 最大间隔超平面2.3 SVM 最优化问题 3 数据分布检验方法3.1 数据分布检验3.2 ...

  8. NLP之NBGBT:基于朴素贝叶斯(count/tfidf+网格搜索+4fCrva)、梯度提升树(w2c+网格搜索+4fCrva)算法对IMDB影评数据集进行文本情感分析(情感二分类预测)

    NLP之NB&GBT:基于朴素贝叶斯(count/tfidf+网格搜索+4fCrva).梯度提升树(w2c+网格搜索+4fCrva)算法对IMDB影评数据集进行文本情感分析(情感二分类预测) ...

  9. ML之NBLoR:利用NB(朴素贝叶斯)、LoR(逻辑斯蒂回归)算法(+TfidfVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析—五分类预测

    ML之NB&LoR:利用NB(朴素贝叶斯).LoR(逻辑斯蒂回归)算法(+TfidfVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析-五分类预测 目录 输出结果 ...

最新文章

  1. java web五: tomcat的目录层次结构以及web应用
  2. 默认方法一种扩展旧代码的方法
  3. ffmpeg.exe 笔记
  4. 提高数据库查询速度的几个思路
  5. linux php mysqldump,Linux Shell脚本之利用mysqldump备份MySQL数据库(详细注解)
  6. echarts 地图常见效果
  7. 基于安卓系统的服药监督系统(一)——可行性研究报告
  8. android集成华为push 6003错误,以及华为低版本crash问题
  9. html表格(table)的基本结构
  10. css中的flow-root属性
  11. html 半框添加,配眼镜全框好还是半框的好?
  12. 鸿蒙界境界划分,修为境界划分
  13. @huangcheng: Fedora 9 GDM开启XDMCP
  14. 安卓获取手机唯一码工具类
  15. css3边框圆角、背景
  16. ARM Linux控制CDS5516
  17. 【244天】我爱刷题系列(3)
  18. java的switch_Java中Switch用法代码示例
  19. css grid 自动高度_10分钟理解CSS3 Grid布局
  20. 阿里云国际站服务器Linux系统磁盘管理怎么操作?

热门文章

  1. 原型系统研究报告撰写_阅书斋 | 王蔷英语教师行动研究:如何撰写行动研究报告...
  2. 原生js实现地址选择组件(三级联动)
  3. 微信登录,返回-6错误
  4. 可怕流氓:百度全家桶
  5. 线程优先级和守护线程
  6. android支付宝rsa加密算法,支付宝支付流程与RSA算法原理
  7. python 计时方法_Python计时器类| cancel()方法与示例
  8. 纯c语言游戏引擎开发,C++ 写个游戏引擎—(基础篇) 1
  9. matlab三相短路电流计算程序_电力系统三相短路计算的MATLAB代码
  10. FBI教你读心术 读书笔记