朴素贝叶斯分类算法

目录(?)[+]

参考资料地址:http://www.cnblogs.com/leoo2sk/archive/2010/09/17/naive-bayesian-classifier.html

我的数据挖掘算法实现源码地址:https://github.com/linyiqun/DataMiningAlgorithm

介绍

要介绍朴素贝叶斯算法(Naive Bayes),那就得先介绍贝叶斯分类算法,贝叶斯分类算法是统计分类算法的一种,他是一类利用概率统计知识进行的一种分类算法。而朴素贝叶斯算法就是里面贝叶斯算法中最简单的一个算法。为什么叫做朴素贝叶斯,因为他里面的各个类条件是独立的,所以一会在后面的计算中会起到很多方便的作用。

朴素贝叶斯算法原理

首先在这里用到了一个概率公式:


P(B|A)的意思是在A事件的情况下,发生B事件的概率,可以理解为概率论中的条件概率,而贝叶斯公式的巨大作用就是对因果关系进行了交换,通过上面的公式就可以计算P(A|B)的概率,只要通过上述的转换。

上面的资源地址上已经对朴素贝叶斯算法的原理描述的非常清楚了,我在他的基础上做了点注释方便于后面代码的理解:

朴素贝叶斯分类的正式定义如下:

1、设为一个待分类项,而每个a为x的一个特征属性。(在后面的例子中x={"Youth", "Medium", "Yes", "Fair"},里面的4个因子为他的特征向量)

2、有类别集合。(在后面的类别中只有buy_computer的分类yes, no,C={yes, no})

3、计算。(在后面的计算的任务就是计算在X事件的条件下,yes和no事件的发生概率,P(Yes|X, P(No|X)))

4、如果,则。(计算出上面的结果值,拥有最大概率的值的yi就是他的分类,这个很好理解,在X条件下,那个分类类型概率高就属于哪个分类,在这里比的就是P(Yes|X, P(No|X))

那么现在的关键就是如何计算第3步中的各个条件概率。我们可以这么做:

1、找到一个已知分类的待分类项集合,这个集合叫做训练样本集。

2、统计得到在各类别下各个特征属性的条件概率估计。即

3、如果各个特征属性是条件独立的,则根据贝叶斯定理有如下推导:

因为分母对于所有类别为常数,因为我们只要将分子最大化皆可。又因为各特征属性是条件独立的,所以有:

p(ai|yi)可以根据数量上的统计进行计算,在后面的程序中会有所体现。

朴素贝叶斯算法的代码实现:

输入的训练集数据input.txt:

  1. RidAgeIncomeStudentCreditRatingBuysComputer
  2. 1YouthHighNoFairNo
  3. 2YouthHighNoExcellentNo
  4. 3MiddleAgedHighNoFairYes
  5. 4SeniorMediumNoFairYes
  6. 5SeniorLowYesFairYes
  7. 6SeniorLowYesExcellentNo
  8. 7MiddleAgedLowYesExcellentYes
  9. 8YouthMediumNoFairNo
  10. 9YouthLowYesFairYes
  11. 10SeniorMediumYesFairYes
  12. 11YouthMediumYesExcellentYes
  13. 12MiddleAgedMediumNoExcellentYes
  14. 13MiddleAgedHighYesFairYes
  15. 14SeniorMediumNoExcellentNo
朴素贝叶斯工具调用类:

  1. packageDataMining_NaiveBayes;
  2. importjava.io.BufferedReader;
  3. importjava.io.File;
  4. importjava.io.FileReader;
  5. importjava.io.IOException;
  6. importjava.util.ArrayList;
  7. importjava.util.HashMap;
  8. importjava.util.Map;
  9. /**
  10. *朴素贝叶斯算法工具类
  11. *
  12. *@authorlyq
  13. *
  14. */
  15. publicclassNaiveBayesTool{
  16. //类标记符,这里分为2类,YES和NO
  17. privateStringYES="Yes";
  18. privateStringNO="No";
  19. //已分类训练数据集文件路径
  20. privateStringfilePath;
  21. //属性名称数组
  22. privateString[]attrNames;
  23. //训练数据集
  24. privateString[][]data;
  25. //每个属性的值所有类型
  26. privateHashMap<String,ArrayList<String>>attrValue;
  27. publicNaiveBayesTool(StringfilePath){
  28. this.filePath=filePath;
  29. readDataFile();
  30. initAttrValue();
  31. }
  32. /**
  33. *从文件中读取数据
  34. */
  35. privatevoidreadDataFile(){
  36. Filefile=newFile(filePath);
  37. ArrayList<String[]>dataArray=newArrayList<String[]>();
  38. try{
  39. BufferedReaderin=newBufferedReader(newFileReader(file));
  40. Stringstr;
  41. String[]tempArray;
  42. while((str=in.readLine())!=null){
  43. tempArray=str.split("");
  44. dataArray.add(tempArray);
  45. }
  46. in.close();
  47. }catch(IOExceptione){
  48. e.getStackTrace();
  49. }
  50. data=newString[dataArray.size()][];
  51. dataArray.toArray(data);
  52. attrNames=data[0];
  53. /*
  54. *for(inti=0;i<data.length;i++){for(intj=0;j<data[0].length;j++){
  55. *System.out.print(""+data[i][j]);}
  56. *
  57. *System.out.print("\n");}
  58. */
  59. }
  60. /**
  61. *首先初始化每种属性的值的所有类型,用于后面的子类熵的计算时用
  62. */
  63. privatevoidinitAttrValue(){
  64. attrValue=newHashMap<>();
  65. ArrayList<String>tempValues;
  66. //按照列的方式,从左往右找
  67. for(intj=1;j<attrNames.length;j++){
  68. //从一列中的上往下开始寻找值
  69. tempValues=newArrayList<>();
  70. for(inti=1;i<data.length;i++){
  71. if(!tempValues.contains(data[i][j])){
  72. //如果这个属性的值没有添加过,则添加
  73. tempValues.add(data[i][j]);
  74. }
  75. }
  76. //一列属性的值已经遍历完毕,复制到map属性表中
  77. attrValue.put(data[0][j],tempValues);
  78. }
  79. }
  80. /**
  81. *在classType的情况下,发生condition条件的概率
  82. *
  83. *@paramcondition
  84. *属性条件
  85. *@paramclassType
  86. *分类的类型
  87. *@return
  88. */
  89. privatedoublecomputeConditionProbably(Stringcondition,StringclassType){
  90. //条件计数器
  91. intcount=0;
  92. //条件属性的索引列
  93. intattrIndex=1;
  94. //yes类标记符数据
  95. ArrayList<String[]>yClassData=newArrayList<>();
  96. //no类标记符数据
  97. ArrayList<String[]>nClassData=newArrayList<>();
  98. ArrayList<String[]>classData;
  99. for(inti=1;i<data.length;i++){
  100. //data数据按照yes和no分类
  101. if(data[i][attrNames.length-1].equals(YES)){
  102. yClassData.add(data[i]);
  103. }else{
  104. nClassData.add(data[i]);
  105. }
  106. }
  107. if(classType.equals(YES)){
  108. classData=yClassData;
  109. }else{
  110. classData=nClassData;
  111. }
  112. //如果没有设置条件则,计算的是纯粹的类事件概率
  113. if(condition==null){
  114. return1.0*classData.size()/(data.length-1);
  115. }
  116. //寻找此条件的属性列
  117. attrIndex=getConditionAttrName(condition);
  118. for(String[]s:classData){
  119. if(s[attrIndex].equals(condition)){
  120. count++;
  121. }
  122. }
  123. return1.0*count/classData.size();
  124. }
  125. /**
  126. *根据条件值返回条件所属属性的列值
  127. *
  128. *@paramcondition
  129. *条件
  130. *@return
  131. */
  132. privateintgetConditionAttrName(Stringcondition){
  133. //条件所属属性名
  134. StringattrName="";
  135. //条件所在属性列索引
  136. intattrIndex=1;
  137. //临时属性值类型
  138. ArrayList<String[]>valueTypes;
  139. for(Map.Entryentry:attrValue.entrySet()){
  140. valueTypes=(ArrayList<String[]>)entry.getValue();
  141. if(valueTypes.contains(condition)
  142. &&!((String)entry.getKey()).equals("BuysComputer")){
  143. attrName=(String)entry.getKey();
  144. }
  145. }
  146. for(inti=0;i<attrNames.length-1;i++){
  147. if(attrNames[i].equals(attrName)){
  148. attrIndex=i;
  149. break;
  150. }
  151. }
  152. returnattrIndex;
  153. }
  154. /**
  155. *进行朴素贝叶斯分类
  156. *
  157. *@paramdata
  158. *待分类数据
  159. */
  160. publicStringnaiveBayesClassificate(Stringdata){
  161. //测试数据的属性值特征
  162. String[]dataFeatures;
  163. //在yes的条件下,x事件发生的概率
  164. doublexWhenYes=1.0;
  165. //在no的条件下,x事件发生的概率
  166. doublexWhenNo=1.0;
  167. //最后也是yes和no分类的总概率,用P(X|Ci)*P(Ci)的公式计算
  168. doublepYes=1;
  169. doublepNo=1;
  170. dataFeatures=data.split("");
  171. for(inti=0;i<dataFeatures.length;i++){
  172. //因为朴素贝叶斯算法是类条件独立的,所以可以进行累积的计算
  173. xWhenYes*=computeConditionProbably(dataFeatures[i],YES);
  174. xWhenNo*=computeConditionProbably(dataFeatures[i],NO);
  175. }
  176. pYes=xWhenYes*computeConditionProbably(null,YES);
  177. pNo=xWhenNo*computeConditionProbably(null,NO);
  178. return(pYes>pNo?YES:NO);
  179. }
  180. }
最后的测试结果是:

  1. YouthMediumYesFair数据的分类为:Yes

朴素贝叶斯算法的注意点:

1、当特征属性值的值类型不是离散值而是连续值的时候,需要通过高斯分布做概率的计算

因此只要计算出训练样本中各个类别中此特征项划分的各均值和标准差,代入上述公式即可得到需要的估计值。均值与标准差的计算在此不再赘述。

2、为了避免统计概率中出现概率为0的情况,在这里引入了Laplace校准,它的思想非常简单,就是对没类别下所有划分的计数加1

参考资料地址:http://www.cnblogs.com/leoo2sk/archive/2010/09/17/naive-bayesian-classifier.html

我的数据挖掘算法实现源码地址:https://github.com/linyiqun/DataMiningAlgorithm

介绍

要介绍朴素贝叶斯算法(Naive Bayes),那就得先介绍贝叶斯分类算法,贝叶斯分类算法是统计分类算法的一种,他是一类利用概率统计知识进行的一种分类算法。而朴素贝叶斯算法就是里面贝叶斯算法中最简单的一个算法。为什么叫做朴素贝叶斯,因为他里面的各个类条件是独立的,所以一会在后面的计算中会起到很多方便的作用。

朴素贝叶斯算法原理

首先在这里用到了一个概率公式:


P(B|A)的意思是在A事件的情况下,发生B事件的概率,可以理解为概率论中的条件概率,而贝叶斯公式的巨大作用就是对因果关系进行了交换,通过上面的公式就可以计算P(A|B)的概率,只要通过上述的转换。

上面的资源地址上已经对朴素贝叶斯算法的原理描述的非常清楚了,我在他的基础上做了点注释方便于后面代码的理解:

朴素贝叶斯分类的正式定义如下:

1、设为一个待分类项,而每个a为x的一个特征属性。(在后面的例子中x={"Youth", "Medium", "Yes", "Fair"},里面的4个因子为他的特征向量)

2、有类别集合。(在后面的类别中只有buy_computer的分类yes, no,C={yes, no})

3、计算。(在后面的计算的任务就是计算在X事件的条件下,yes和no事件的发生概率,P(Yes|X, P(No|X)))

4、如果,则。(计算出上面的结果值,拥有最大概率的值的yi就是他的分类,这个很好理解,在X条件下,那个分类类型概率高就属于哪个分类,在这里比的就是P(Yes|X, P(No|X))

那么现在的关键就是如何计算第3步中的各个条件概率。我们可以这么做:

1、找到一个已知分类的待分类项集合,这个集合叫做训练样本集。

2、统计得到在各类别下各个特征属性的条件概率估计。即

3、如果各个特征属性是条件独立的,则根据贝叶斯定理有如下推导:

因为分母对于所有类别为常数,因为我们只要将分子最大化皆可。又因为各特征属性是条件独立的,所以有:

p(ai|yi)可以根据数量上的统计进行计算,在后面的程序中会有所体现。

朴素贝叶斯算法的代码实现:

输入的训练集数据input.txt:

  1. RidAgeIncomeStudentCreditRatingBuysComputer
  2. 1YouthHighNoFairNo
  3. 2YouthHighNoExcellentNo
  4. 3MiddleAgedHighNoFairYes
  5. 4SeniorMediumNoFairYes
  6. 5SeniorLowYesFairYes
  7. 6SeniorLowYesExcellentNo
  8. 7MiddleAgedLowYesExcellentYes
  9. 8YouthMediumNoFairNo
  10. 9YouthLowYesFairYes
  11. 10SeniorMediumYesFairYes
  12. 11YouthMediumYesExcellentYes
  13. 12MiddleAgedMediumNoExcellentYes
  14. 13MiddleAgedHighYesFairYes
  15. 14SeniorMediumNoExcellentNo
朴素贝叶斯工具调用类:

  1. packageDataMining_NaiveBayes;
  2. importjava.io.BufferedReader;
  3. importjava.io.File;
  4. importjava.io.FileReader;
  5. importjava.io.IOException;
  6. importjava.util.ArrayList;
  7. importjava.util.HashMap;
  8. importjava.util.Map;
  9. /**
  10. *朴素贝叶斯算法工具类
  11. *
  12. *@authorlyq
  13. *
  14. */
  15. publicclassNaiveBayesTool{
  16. //类标记符,这里分为2类,YES和NO
  17. privateStringYES="Yes";
  18. privateStringNO="No";
  19. //已分类训练数据集文件路径
  20. privateStringfilePath;
  21. //属性名称数组
  22. privateString[]attrNames;
  23. //训练数据集
  24. privateString[][]data;
  25. //每个属性的值所有类型
  26. privateHashMap<String,ArrayList<String>>attrValue;
  27. publicNaiveBayesTool(StringfilePath){
  28. this.filePath=filePath;
  29. readDataFile();
  30. initAttrValue();
  31. }
  32. /**
  33. *从文件中读取数据
  34. */
  35. privatevoidreadDataFile(){
  36. Filefile=newFile(filePath);
  37. ArrayList<String[]>dataArray=newArrayList<String[]>();
  38. try{
  39. BufferedReaderin=newBufferedReader(newFileReader(file));
  40. Stringstr;
  41. String[]tempArray;
  42. while((str=in.readLine())!=null){
  43. tempArray=str.split("");
  44. dataArray.add(tempArray);
  45. }
  46. in.close();
  47. }catch(IOExceptione){
  48. e.getStackTrace();
  49. }
  50. data=newString[dataArray.size()][];
  51. dataArray.toArray(data);
  52. attrNames=data[0];
  53. /*
  54. *for(inti=0;i<data.length;i++){for(intj=0;j<data[0].length;j++){
  55. *System.out.print(""+data[i][j]);}
  56. *
  57. *System.out.print("\n");}
  58. */
  59. }
  60. /**
  61. *首先初始化每种属性的值的所有类型,用于后面的子类熵的计算时用
  62. */
  63. privatevoidinitAttrValue(){
  64. attrValue=newHashMap<>();
  65. ArrayList<String>tempValues;
  66. //按照列的方式,从左往右找
  67. for(intj=1;j<attrNames.length;j++){
  68. //从一列中的上往下开始寻找值
  69. tempValues=newArrayList<>();
  70. for(inti=1;i<data.length;i++){
  71. if(!tempValues.contains(data[i][j])){
  72. //如果这个属性的值没有添加过,则添加
  73. tempValues.add(data[i][j]);
  74. }
  75. }
  76. //一列属性的值已经遍历完毕,复制到map属性表中
  77. attrValue.put(data[0][j],tempValues);
  78. }
  79. }
  80. /**
  81. *在classType的情况下,发生condition条件的概率
  82. *
  83. *@paramcondition
  84. *属性条件
  85. *@paramclassType
  86. *分类的类型
  87. *@return
  88. */
  89. privatedoublecomputeConditionProbably(Stringcondition,StringclassType){
  90. //条件计数器
  91. intcount=0;
  92. //条件属性的索引列
  93. intattrIndex=1;
  94. //yes类标记符数据
  95. ArrayList<String[]>yClassData=newArrayList<>();
  96. //no类标记符数据
  97. ArrayList<String[]>nClassData=newArrayList<>();
  98. ArrayList<String[]>classData;
  99. for(inti=1;i<data.length;i++){
  100. //data数据按照yes和no分类
  101. if(data[i][attrNames.length-1].equals(YES)){
  102. yClassData.add(data[i]);
  103. }else{
  104. nClassData.add(data[i]);
  105. }
  106. }
  107. if(classType.equals(YES)){
  108. classData=yClassData;
  109. }else{
  110. classData=nClassData;
  111. }
  112. //如果没有设置条件则,计算的是纯粹的类事件概率
  113. if(condition==null){
  114. return1.0*classData.size()/(data.length-1);
  115. }
  116. //寻找此条件的属性列
  117. attrIndex=getConditionAttrName(condition);
  118. for(String[]s:classData){
  119. if(s[attrIndex].equals(condition)){
  120. count++;
  121. }
  122. }
  123. return1.0*count/classData.size();
  124. }
  125. /**
  126. *根据条件值返回条件所属属性的列值
  127. *
  128. *@paramcondition
  129. *条件
  130. *@return
  131. */
  132. privateintgetConditionAttrName(Stringcondition){
  133. //条件所属属性名
  134. StringattrName="";
  135. //条件所在属性列索引
  136. intattrIndex=1;
  137. //临时属性值类型
  138. ArrayList<String[]>valueTypes;
  139. for(Map.Entryentry:attrValue.entrySet()){
  140. valueTypes=(ArrayList<String[]>)entry.getValue();
  141. if(valueTypes.contains(condition)
  142. &&!((String)entry.getKey()).equals("BuysComputer")){
  143. attrName=(String)entry.getKey();
  144. }
  145. }
  146. for(inti=0;i<attrNames.length-1;i++){
  147. if(attrNames[i].equals(attrName)){
  148. attrIndex=i;
  149. break;
  150. }
  151. }
  152. returnattrIndex;
  153. }
  154. /**
  155. *进行朴素贝叶斯分类
  156. *
  157. *@paramdata
  158. *待分类数据
  159. */
  160. publicStringnaiveBayesClassificate(Stringdata){
  161. //测试数据的属性值特征
  162. String[]dataFeatures;
  163. //在yes的条件下,x事件发生的概率
  164. doublexWhenYes=1.0;
  165. //在no的条件下,x事件发生的概率
  166. doublexWhenNo=1.0;
  167. //最后也是yes和no分类的总概率,用P(X|Ci)*P(Ci)的公式计算
  168. doublepYes=1;
  169. doublepNo=1;
  170. dataFeatures=data.split("");
  171. for(inti=0;i<dataFeatures.length;i++){
  172. //因为朴素贝叶斯算法是类条件独立的,所以可以进行累积的计算
  173. xWhenYes*=computeConditionProbably(dataFeatures[i],YES);
  174. xWhenNo*=computeConditionProbably(dataFeatures[i],NO);
  175. }
  176. pYes=xWhenYes*computeConditionProbably(null,YES);
  177. pNo=xWhenNo*computeConditionProbably(null,NO);
  178. return(pYes>pNo?YES:NO);
  179. }
  180. }
最后的测试结果是:

  1. YouthMediumYesFair数据的分类为:Yes

朴素贝叶斯算法的注意点:

1、当特征属性值的值类型不是离散值而是连续值的时候,需要通过高斯分布做概率的计算

因此只要计算出训练样本中各个类别中此特征项划分的各均值和标准差,代入上述公式即可得到需要的估计值。均值与标准差的计算在此不再赘述。

2、为了避免统计概率中出现概率为0的情况,在这里引入了Laplace校准,它的思想非常简单,就是对没类别下所有划分的计数加1

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值