朴素贝叶斯算法分析及java 实现

1. 先引入一个简单的例子

出处:http://www.ruanyifeng.com/blog/2013/12/naive_bayes_classifier.html

一、病人分类的例子

让我从一个例子开始讲起,你会看到贝叶斯分类器很好懂,一点都不难。

某个医院早上收了六个门诊病人,如下表。

  症状  职业   疾病
  打喷嚏 护士   感冒
  打喷嚏 农夫   过敏
  头痛  建筑工人 脑震荡
  头痛  建筑工人 感冒
  打喷嚏 教师   感冒
  头痛  教师   脑震荡

现在又来了第七个病人,是一个打喷嚏的建筑工人。请问他患上感冒的概率有多大?

根据贝叶斯定理:

 P(A|B) = P(B|A) P(A) / P(B)

可得

P(感冒|打喷嚏x建筑工人)

    = P(打喷嚏x建筑工人|感冒) x P(感冒)
    / P(打喷嚏x建筑工人)
假定"打喷嚏"和"建筑工人"这两个特征是独立的,因此,上面的等式就变成了
   P(感冒|打喷嚏x建筑工人)
    = P(打喷嚏|感冒) x P(建筑工人|感冒) x P(感冒)
    / P(打喷嚏) x P(建筑工人)
这是可以计算的。
  P(感冒|打喷嚏x建筑工人)
    = 0.66 x 0.33 x 0.5 / 0.5 x 0.33
    = 0.66

因此,这个打喷嚏的建筑工人,有66%的概率是得了感冒。同理,可以计算这个病人患上过敏或脑震荡的概率。比较这几个概率,就可以知道他最可能得什么病。

这就是贝叶斯分类器的基本方法:在统计资料的基础上,依据某些特征,计算各个类别的概率,从而实现分类。

二、朴素贝叶斯分类器的公式

假设某个体有n项特征(Feature),分别为F1、F2、...、Fn。现有m个类别(Category),分别为C1、C2、...、Cm。贝叶斯分类器就是计算出概率最大的那个分类,也就是求下面这个算式的最大值:

 P(C|F1F2...Fn)
  = P(F1F2...Fn|C)P(C) / P(F1F2...Fn)

由于 P(F1F2...Fn) 对于所有的类别都是相同的,可以省略,问题就变成了求

 P(F1F2...Fn|C)P(C)

的最大值。

朴素贝叶斯分类器则是更进一步,假设所有特征都彼此独立,因此

 P(F1F2...Fn|C)P(C)
  = P(F1|C)P(F2|C) ... P(Fn|C)P(C)

上式等号右边的每一项,都可以从统计资料中得到,由此就可以计算出每个类别对应的概率,从而找出最大概率的那个类。

虽然"所有特征彼此独立"这个假设,在现实中不太可能成立,但是它可以大大简化计算,而且有研究表明对分类结果的准确性影响不大。

下面再通过两个例子,来看如何使用朴素贝叶斯分类器。

2. 举例说明(采用打球的例子)

通过上面的例子我们知道,朴素贝叶斯训练阶段要做的事情就是求: P(F1|C)P(F2|C)
... P(Fn|C)P(C)

2.1 下面以打球的例子分析:

datafile/naivebayes/train/in/weather.nominal.arff

#存放做决策的属性,一般是或否
@decision
yes,no
@attribute outlook {sunny, overcast, rainy}
@attribute temperature {hot, mild, cool}
@attribute humidity {high, normal}
@attribute windy {TRUE, FALSE}
@data
sunny,hot,high,FALSE,no
sunny,hot,high,TRUE,no
overcast,hot,high,FALSE,yes
rainy,mild,high,FALSE,yes
rainy,cool,normal,FALSE,yes
rainy,cool,normal,TRUE,no
overcast,cool,normal,TRUE,yes
sunny,mild,high,FALSE,no
sunny,cool,normal,FALSE,yes
rainy,mild,normal,FALSE,yes
sunny,mild,normal,TRUE,yes
overcast,mild,high,TRUE,yes
overcast,hot,normal,FALSE,yes
rainy,mild,high,TRUE,no

2.2训练阶段要做的事情就是求出以下各个值的概率:(先放结果再分析)

datafile/naivebayes/train/out/trainresult.arff

@decision P(yes) {0.6428571428571429}
@decision P(no) {0.35714285714285715}
@data
P(outlook=sunny|yes),0.2222222222222222
P(outlook=sunny|no),0.6
P(outlook=overcast|yes),0.4444444444444444
P(outlook=overcast|no),0.0
P(outlook=rainy|yes),0.3333333333333333
P(outlook=rainy|no),0.4
P(temperature=hot|yes),0.2222222222222222
P(temperature=hot|no),0.4
P(temperature=mild|yes),0.4444444444444444
P(temperature=mild|no),0.4
P(temperature=cool|yes),0.3333333333333333
P(temperature=cool|no),0.2
P(humidity=high|yes),0.3333333333333333
P(humidity=high|no),0.8
P(humidity=normal|yes),0.6666666666666666
P(humidity=normal|no),0.2
P(windy=TRUE|yes),0.3333333333333333
P(windy=TRUE|no),0.6
P(windy=FALSE|yes),0.6666666666666666
P(windy=FALSE|no),0.4
</pre></div><h2>2.3上面的各个概率计算过程如下:</h2><p></p><pre code_snippet_id="408634" snippet_file_name="blog_20140627_4_590110" name="code" class="html">P(yes)=9/14 (在训练集中,yes出现9次,总数是14 )
P(no)=5/14
P(outlook=sunny|yes)=2/9(同时为sunny和yes的记录出现了2次,而yes总数出现了9次)
P(outlook=sunny|no)=3/5 (同时为sunny和no的记录出现了3次,no出现了5次)

其它的计算一样,这里不例举了。

2.4  测试:

求 (sunny,hot,high,FALSE) 属于yes还是no呢?

为了显示好看,把(sunny,hot,high,FALSE) 用1来表示

计算方法如下:

属于yes的概率(其它这里严格意义的概率,因为没有除以分母)

P(1|yes)= P(yes)*P(sunny|yes)*P(hot|yes)*P(high|yes)*P(FALSE|yes)=0.6428571428571429*0.2222222222222222*0.2222222222222222*0.3333333333333333*0.6666666666666666=0.007(约等)
P(1|no)=0.027
显然它属于no的概率大一点,判定它为no.

2.5 零频问题

以上计算没有考虑零频问题,实际的计算中应该避免零频问题,即在每个项计数时加1。

3.数学语言描述

关于数学公式的描述,这位大牛写得非常详细,建议大家看一看。

http://www.cnblogs.com/leoo2sk/archive/2010/09/17/naive-bayesian-classifier.html

3.1贝叶斯定理:

3.2 推导

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

1、设为一个待分类项,而每个a为x的一个特征属性。

2、有类别集合

3、计算

4、如果,则

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

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

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

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

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

5.测试结果

下面结果对各项统计加1,为了避免零频问题。

sunny,hot,high,FALSE   判断的结果是:no	      --参考数值是:0.059
overcast,mild,high,TRUE   判断的结果是:yes	      --参考数值是:0.028
overcast,hot,normal,FALSE   判断的结果是:yes	      --参考数值是:0.052
rainy,mild,high,TRUE   判断的结果是:no	      --参考数值是:0.059

在实际中应随机抽取80%数据作为样本集,20%作为测试集,本例没考虑这点。

4.JAVA实现

详细源码请到我的Github上下载:

https://github.com/Bellonor/myHadoopProject/tree/master/com.homework/src/sequence/machinelearning/naivebayes/sequence/machinelearning/naivebayes/bayesdemo

时间匆忙,写例子为讲解。代码中各种漏洞请各位指出。谢谢!

以下仅给出训练部分的代码:

package sequence.machinelearning.naivebayes.bayesdemo;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.LinkedList;
/**
 * 案例:http://www.cnblogs.com/zhangchaoyang/articles/2586402.html
 * @author Jamas
 *  也参考了这篇文章:http://www.cnblogs.com/leoo2sk/archive/2010/09/17/naive-bayesian-classifier.html
 */
public class Train {

    public static LinkedList<String> lisatt = new LinkedList<String>(); // 存储属性的名称:outlook,temperature,humidity,windy
    public static LinkedList<ArrayList<String>> lisvals = new LinkedList<ArrayList<String>>(); //outlook:sunny,overcast,rainy 存储每个属性的取值,属性的特征
    public static LinkedList<String[]> listdata = new LinkedList<String[]>();; // 原始数据

    public static final String patternString = "@attribute(.*)[{](.*?)[}]";
    //存储分类,比如,是,否。再比如:检测SNS社区中不真实账号,是真实用户还是僵尸用户
    public static LinkedList<String> sort=new LinkedList<String>();

    //计算P(F1|C)P(F2|C)...P(Fn|C)P(C),并保存为文本文件
    /**
     * 为了避免零频问题,对每个计数加1,只要数量足够大,加1是可以忽略的
     * @throws IOException
     */
    public void CountProbility() throws IOException{

        String src="datafile/naivebayes/train/out/trainresult.arff";
        delfile(src);
        File file=new File(src);
        if(file.exists())
            file.createNewFile();
        FileOutputStream out=new FileOutputStream(file,true);
        Map<String,Integer> map=new HashMap<String,Integer>();
    	//先计算判定结果的概率,保存为文件
    	for(int i=0;i<sort.size();i++){
            //第一个for对取出sort,第二个for对data中的sort进行计数
    		//避免零频问题,对各项计数加1
    		Integer sum=1;
            String sortname=sort.get(i);
            Double probability=0.0;

            for(int j=0;j<listdata.size();j++){
    			String[] line=listdata.get(j);
    			if(line[line.length-1].equals(sortname)){
    				sum=sum+1;
    			}
     	    }
    		map.put(sortname, sum);
    		probability=Double.valueOf(sum)/Double.valueOf(listdata.size());
    		//写入文件
    		StringBuffer sb=new StringBuffer();
            sb.append("@decision P("+sortname+") {"+probability.toString()+"}\n");//如果不加"/n"则不能实现换行。
            System.out.print(sb.toString());

            out.write(sb.toString().getBytes("utf-8"));
    	}
    	out.write("@data\n".getBytes("utf-8"));
    	System.out.print("@data\n");
    	//先计算判定结果的概率,保存为文件
    	//out.close(); //到最后写完的时候再关闭
    	//分别统计P(F1|C)P(F2|C)...P(Fn|C)的个数,参考:http://www.ruanyifeng.com/blog/2013/12/naive_bayes_classifier.html
    	 //对属性进行循环
        for(int i=0;i<lisatt.size();i++){

        	String attname=lisatt.get(i);
        	List<String> lisval=lisvals.get(i);
        	//对属性的特征进行循环
        	for(int j=0;j<lisval.size();j++){
        		String attval=lisval.get(j);
        		//先取出sort(yes 还是no情况)
        		for(int n=0;n<sort.size();n++){
        			//避免零频问题,对各项计数加1
        			Integer sum=1;
                    String sortname=sort.get(n);
                    Double probability=0.0;

                    //取出数据集进行for
                    for(int k=0;k<listdata.size();k++){
            			String[] line=listdata.get(k);
            			if(line[line.length-1].equals(sortname)&&line[i].equals(attval)){
            				sum=sum+1;
            			}
             	    }

            		probability=Double.valueOf(sum)/Double.valueOf(map.get(sortname));
            		//写入文件
            		StringBuffer sb=new StringBuffer();
                    sb.append("P("+attname+"="+attval+"|"+sortname+"),"+probability+"\n");//如果不加"/n"则不能实现换行。
                    System.out.print(sb.toString());
                    out.write(sb.toString().getBytes("utf-8"));
        		}

        	}
        }
        out.close();
    }

    //读取arff文件,给attribute、attributevalue、data赋值
    public void readARFF(File file) {
        try {
            FileReader fr = new FileReader(file);
            BufferedReader br = new BufferedReader(fr);
            String line;
            Pattern pattern = Pattern.compile(patternString);
            while ((line = br.readLine()) != null) {
            	if (line.startsWith("@decision")) {
                   line = br.readLine();
                        if(line=="")
                            continue;
                        String[] type = line.split(",");
                        for(int i=0;i<type.length;i++){
                        	sort.add(type[i].trim());
                        }
                }
            	Matcher matcher = pattern.matcher(line);
                if (matcher.find()) {
                	lisatt.add(matcher.group(1).trim());
                    String[] values = matcher.group(2).split(",");
                    ArrayList<String> al = new ArrayList<String>(values.length);
                    for (String value : values) {
                        al.add(value.trim());
                    }
                    lisvals.add(al);
                } else if (line.startsWith("@data")) {
                    while ((line = br.readLine()) != null) {
                        if(line=="")
                            continue;
                        String[] row = line.split(",");
                        listdata.add(row);
                    }
                } else {
                    continue;
                }
            }
            br.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		Train train=new Train();
		train.readARFF(new File("datafile/naivebayes/train/in/weather.nominal.arff"));
		train.CountProbility();

	}
	public void delfile(String filepath){
		   File file=new File(filepath);
		       if(file.exists())
		      {
		           //file.createNewFile();
				   file.delete();
		       }    

	   }
}

朴素贝叶斯算法分析及java 实现

时间: 2024-10-12 13:00:54

朴素贝叶斯算法分析及java 实现的相关文章

利用朴素贝叶斯算法进行分类-Java代码实现

http://www.crocro.cn/post/286.html 利用朴素贝叶斯算法进行分类-Java代码实现 鳄鱼  3个月前 (12-14)  分类:机器学习  阅读(44)  评论(0) Java package cn.crocro.classifier; import java.util.ArrayList; /** * 朴素贝叶斯分类器,只能针对有限个情况的分类下面是实例代码 * * @author 鳄鱼 * */ public class NaiveBayesClassifier

挖掘算法(1)朴素贝叶斯算法

原文:http://www.blogchong.com/post/NaiveBayes.html 1 文档说明 该文档为朴素贝叶斯算法的介绍和分析文档,并且结合应用实例进行了详细的讲解. 其实朴素贝叶斯的概念以及流程都被写烂了,之所以写这些是方便做个整理,记录备忘.而实例部分进行了详细的描述,网络上该实例比较简单,没有过程. 至于最后部分,则是对朴素贝叶斯的一个扩展了,当然只是简单的描述了一下过程,其中涉及到的中文分词以及TFIDF算法,有时间再具体补上. 2 算法介绍 2.1 贝叶斯定理 (1

朴素贝叶斯之MapReduce版

1,统计词出现的次数 1/计算类别的先验概率 *输入格式:类别+文档id+文档词(切分成A,b,c) *输出格式:类别+文档出现次数+文档出现的词的总数 2/计算每个词的条件概率 *输入格式:类别+文档id+文档词(切分成A,b,c) *输出格式:类别+词+词的总数 3/假设二分类问题-计算概率值 * 1类别+文档出现次数+文档出现的词的总数 * 2类别+词+词的总数 * 3类别+词+log(词的总数/文档出现的词的总数),类别-log(文档出现次数/sum(文档出现次数)) * 输入格式:类别

斯坦福机器学习实现与分析之六(朴素贝叶斯)

朴素贝叶斯(Naive Bayes)适用于离散特征的分类问题,对于连续问题则需将特征离散化后使用.朴素贝叶斯有多元伯努利事件模型和多项式事件模型,在伯努利事件模型中,特征每一维的值只能是0或1,而多项式模型中特征每一维的值可取0到N之间的整数,因此伯努利模型是多项式模型的一种特例,下面的推导就直接使用伯努利模型. 朴素贝叶斯原理推导 与GDA类似,朴素贝叶斯对一个测试样本分类时,通过比较p(y=0|x)和p(y=1|x)来进行决策.根据贝叶斯公式: \( \begin{aligned} p(y=

机器学习四 -- 基于概率论的分类方法:朴素贝叶斯

基于概率的分类方法:朴素贝叶斯 贝叶斯决策理论 朴素贝叶斯是贝叶斯决策理论的一部分,所以在讲解朴素贝叶斯之前我们先快速简单了解一下贝叶斯决策理论知识. 贝叶斯决策理论的核心思想:选择具有最高概率的决策.比如我们毕业选择就业方向,选择C++方向的概率为0.3,选择Java的概率为0.2,选择机器学习的概率为0.5.那么我们就把这样的一位毕业生就业方向归类为机器学习方向. 条件概率 什么是条件概率?事件A在另一个事件B已知发生条件下的发生概率,记为P(A|B),读作“在B条件下A的概率”. 例子1:

朴素贝叶斯学习

朴素贝叶斯,为什么叫"朴素",就在于是假定所有的特征之间是"独立同分布"的.这样的假设肯定不是百分百合理的,在现实中,特征与特征之间肯定还是存在千丝万缕的联系的,但是假设特征之间是"独立同分布",还是有合理性在里面,而且针对某些特定的任务,用朴素贝叶斯得到的效果还不错,根据"实践是检验真理的唯一标准",这个模型就具备意义了.这其实和那个"马尔科夫"假设有类似的地方. 朴素贝叶斯的一个思想是,根据现有的一些材

《机器学习实战》笔记——朴素贝叶斯

运用贝叶斯公式(朴素贝叶斯假设每个特征每个特征都是独立的)可以解决的问题有,已知某些特征,用来判断某情况发生的可能性大小,设置可能性最大的情况作为预测值. 是一种监督算法. 广泛应用于垃圾邮件检测等等. 1 # _*_coding:utf-8_*_ 2 from numpy import * 3 4 # 4-1 词表到向量的转换函数(实验样本) 5 def loadDataSet(): 6 postingList = [['my', 'dog', 'has', 'flea', 'problems

关于朴素贝叶斯

朴素贝叶斯或者说基于贝叶斯理论的决策方法都是生成式模型.那么什么是生成式模型呢?生成式模型和判别式模型的概念分别是什么?大体来说,给定数据集x,可以直接通过建模P(c|x)来预测c,这样得到的是判别式模型.像BP网络,支持向量机,决策树都属于判别式模型.如果先对联合概率分布P(x,c)建模,然后再由此获得P(c|x),这样得到的生成式模型,例如朴素贝叶斯. 朴素贝叶斯应用的先决条件是"属性条件独立假设",即已知类别,假设所有属性相互独立.

我理解的朴素贝叶斯模型

我理解的朴素贝叶斯模型 我想说:"任何事件都是条件概率."为什么呢?因为我认为,任何事件的发生都不是完全偶然的,它都会以其他事件的发生为基础.换句话说,条件概率就是在其他事件发生的基础上,某事件发生的概率. 条件概率是朴素贝叶斯模型的基础. 假设,你的xx公司正在面临着用户流失的压力.虽然,你能计算用户整体流失的概率(流失用户数/用户总数).但这个数字并没有多大意义,因为资源是有限的,利用这个数字你只能撒胡椒面似的把钱撒在所有用户上,显然不经济.你非常想根据用户的某种行为,精确地估计一