为您推荐:
精华内容
最热下载
问答
  • 5星
    10.92MB weixin_44510615 2021-07-02 15:47:03
  • 5星
    403KB alongiii 2021-01-04 10:40:20
  • 5星
    17KB younow22 2021-02-15 20:33:07
  • 5星
    12.97MB weixin_42163563 2021-08-19 18:35:43
  • 5星
    14KB weixin_42696333 2021-09-10 17:36:28
  • 5星
    29KB m0_52957036 2020-04-29 07:50:59
  • 5星
    6.25MB bala5569 2021-03-06 10:01:26
  • 61KB m0_52957036 2020-08-20 00:45:55
  • 121KB m0_52957036 2019-12-24 21:02:09
  • 49KB weixin_38705723 2020-12-20 21:58:07
  • 39KB weixin_38727087 2021-05-22 06:33:58
  • 66KB weixin_38746926 2021-01-06 21:29:19
  • 67KB weixin_38694006 2021-01-20 11:21:52
  • 基于朴素贝叶斯分类器文本分类算法(C语言)基于朴素贝叶斯分类器文本分类算法(C语言)基于朴素贝叶斯分类器文本分类算法(C语言).txt两个人吵架,先说对不起的人,并不是认输了,并不是原谅了。他只是比对方更...

    基于朴素贝叶斯分类器的文本分类算法(C语言)基于朴素贝叶斯分类器的文本分类算法(C语言)

    基于朴素贝叶斯分类器的文本分类算法(C语言).txt两个人吵架,先说对不起的人,并不是认输了,并不是原谅了。他只是比对方更珍惜这份感情。#include

    #include

    #include //_getcwd(), _chdir()

    #include //_MAX_PATH, system()

    #include //_finddata_t, _findfirst(), _findnext(), _findclose()

    char vocabulary[1000][20];/*声明公有二维数组,用来存储分割好的单词*/

    /*=================将要分类的文本分割成单词存储在二维数组vocabulary中================*/

    //@输入参数:要分类的文本

    //@输出参数:该文本中总单词数

    int SplitToWord(char text[])

    {

    int i=0;

    char seps[]=", .\n"; /*定义单词的分隔符*/

    char *substring;

    /******利用分隔符将文本内容分割成单词并存储******/

    substring=strtok(text,seps);

    while(substring!=NULL)

    {

    strcpy(vocabulary[i],substring);//将单词存储到vocabulary数组中

    substring=strtok(NULL,seps);

    i++;

    }

    return i; //返回一共多少个单词

    }

    /*===============================计算该目录下的文件数================================*/

    //@输入参数:无

    //@输出参数:该目录下.txt文件数

    int CountDirectory()

    {

    int count=0; //txt文件计数器

    long hFile;

    _finddata_t fileinfo;

    /********查找.txt文件,记录文件数**********/

    if ((hFile=_findfirst("*.txt",&fileinfo))!=-1L)

    {

    do

    {

    count++;

    } while (_findnext(hFile,&fileinfo) == 0);

    }

    return count;

    }

    /*===================================计算某类别中∏P(ai|vj)===================================*/

    //@输入参数:分类文本中单词数

    //@输出参数:该类别下∏P(ai|vj)

    float CalculateWordProbability(int wordCount)

    {

    int countSame; //分类文本中的某单词在所有训练样本中出现次数

    int countAll=0; //训练样本中总单词数

    char token;

    FILE *fp;

    float wordProbability=1; //为后面联乘做准备

    int i,j;

    long hFile;

    _finddata_t fileinfo;

    for(j=0;j

    {

    countSame=0;

    countAll=0;

    if((hFile=_findfirst("*.txt",&fileinfo))!=-1L) //对于该类别下每一个.txt文本

    {

    do

    {

    if((fp=fopen(,"r"))==NULL) //是否能打开该文本

    {

    printf("Sorry!Cannot open the file!\n");

    exit(0);

    }

    /********存储此.txt文件中每个单词并与分类文本的单词作比较*******/

    while((token = fgetc(fp)) != EOF)

    {

    char keyword[1024];

    i = 0;

    keyword[0] = token; // 将每个词第一个字符赋给数组第一个元素

    while ((keyword[++i] = fge

    展开全文
    weixin_34274601 2021-05-23 01:28:38
  • 15KB weixin_42139429 2021-05-16 20:00:40
  • 2KB colourful_sky 2018-05-14 11:27:41
  • 9KB weixin_39840588 2019-08-11 03:33:21
  • 17KB qq_45531594 2020-08-31 15:07:10
  • 1.14MB zzz_cming 2019-04-24 19:44:03
  • 4星
    249KB u010981582 2016-01-27 17:04:50
  • 2KB zhoujb123 2016-10-14 13:31:53
  • 4KB qq_39003406 2019-06-14 10:17:17
  • 1.03MB weixin_42143161 2021-06-09 17:23:24
  • 6KB weixin_38653155 2021-05-11 19:31:31
  • 5星
    50.95MB qq_43245200 2020-04-08 16:19:10
  • 1、用MapReduce算法实现贝叶斯分类器的训练过程,并输出训练模型; 2、用输出的模型对测试集文档进行分类测试。测试过程可基于单机Java程序,也可以是MapReduce程序。输出每个测试文档的分类结果; 3、利用测试...
    1. 实验要求
    2. 题目要求

    1、用MapReduce算法实现贝叶斯分类器的训练过程,并输出训练模型;

    2、用输出的模型对测试集文档进行分类测试。测试过程可基于单机Java程序,也可以是MapReduce程序。输出每个测试文档的分类结果;

    3、利用测试文档的真实类别,计算分类模型的PrecisionRecallF1值。

    2.实验环境

    实验平台:VMware Workstation10

    虚拟机系统:Suse11

    集群环境:主机名master  ip:192.168.226.129

    从机名slave1  ip:192.168.226.130

    1. 贝叶斯分类器理论介绍

    贝叶斯分类器的分类原理是通过某对象的先验概率,利用贝叶斯公式计算出其后验概率,即该对象属于某一类的概率,选择具有最大后验概率的类作为该对象所属的类。

    应用贝叶斯分类器进行分类主要分成两阶段。第一阶段是贝叶斯统计分类器的学习阶段,即根据训练数据集训练得出训练模型;第二阶段是贝叶斯分类器的推理阶段,即根据训练模型计算属于各个分类的概率,进行分类。

    贝叶斯公式如下:

    IMG_256

    其中AB分别为两个不同的事件,P(A)A先验概率P(A|B)是已知B发生后A条件概率,也由于得自B的取值而被称作A后验概率。而上式就是用事件B的先验概率来求它的后验概率。

    1. 贝叶斯分类器训练的MapReduce算法设计

    3.1贝叶斯文本分类流程图

    3.2贝叶斯文本分类详细步骤

           整个文档归类过程可以分为以下步骤:

      1. 测试数据打包。将训练数据集中的大量小文本打包为SequencedFileMapReduce程序)。
      2. 文档统计以及单词统计。将1中输出的SequencedFile作为输入,分别进行文档个数统计DocCount(MapReduce程序)和各个分类下单词个数统计WordCount(MapReduce程序)
      3. 测试数据打包。将测试数据集中的大量小文本打包为SequcedFileMapReduce程序)。
      4. 文档归类。将2中输出的文档统计和单词统计的结果,分别计算文档的先验概率和单词在各个分类下的条件概率,然后将3中输出的SequencedFile作为输入,计算测试文本属于各个分类的概率,并选择其中最大概率的分类作为该文档的所属分类。

    3.3具体算法设计

    一个Country有多个news.txt, 一个news 有多个word

    我们所设计的算法最后是要得到随机抽取一个txt文档,它最有可能属于哪个国家类别,也就是我们要得到它属于哪个国家的概率最大,把它转化为数学公式也就是:

             3-1

    为了便于比较,我们将上式取对数得到:

           3-2

    其中Num(Wi)表示该txt文档中单词Wi的个数;P(C|Wi) 表示拿出一个单词Wi,其属于国家C的后验概率。根据贝叶斯公式有:P(C|W) = P(W|C)*P(C)/P(W),其中:

    P(W|C):国家Cnews中单词W出现的概率,根据式3-2,不能使该概率为0,所以我们约定每个国家都至少包含每个单词一次,也就是在统计单词数量时,都自动的加1,就有:

         3-3

    P(C):国家C出现的概率(正比于其所含txt文件数);

    P(W):单词W在整个测试集中出现的概率。

    根据上面的贝叶斯公式我们设计的MapReduce算法如下:

    1. 按比例选取测试文档,其比例大致为国家包含文档数的相对比例;
    2. Map操作:一一遍历文档,得到<<C, Wi> , 1>
    3. Reduce操作:

    合并<<C, W> , 1> 得到国家C中含有单词Wi的个数<<C, Wi> , ni>+1,记为N(C,Wi)

    得到国家C中含有的单词总数,记为N(C)

    得到测试集中单词W的总数,记为N(W)

    再由得到测试集的单词总数,记为N

    则可求得P(W|C) = N(C,W)/N(C)P(C) = N(C)/NP(W) = N(W)/N

     

    3.4MapReduceData Flow示意图

    1. 源代码清单

    本实验中的主要代码如下所示

    4.1 SmallFilesToSequenceFileConverter.java      小文件集合打包工具类MapReduce程序

    4.2 WholeFileInputFormat.java      支持类:递归读取指定目录下的所有文件

    4.3 WholeFileRecordReader.java 支持类:读取单个文件的全部内容

    4.4 DocCount.java     文档统计MapReduce程序

    4.5 WordCount.java   单词统计MapReduce程序

    4.6 DocClassification.java   测试文档分类MapReduce程序

    详细代码如下:

    4.1 SmallFilesToSequenceFileConverter.java 其中MapReduce关键代码如下:

    publicclass SmallFilesToSequenceFileConverter extends Configured implements Tool {

     

        staticclass SequenceFileMapper extends Mapper<NullWritable, BytesWritable, Text, BytesWritable> {

     

           private String fileNameKey// 被打包的小文件名作为key,表示为Text对象

           private String classNameKey// 当前文档所在的分类名

     

           @Override// 重新实现setup方法,进行map任务的初始化设置

           protectedvoid setup(Context contextthrows IOException, InterruptedException {

               InputSplit split = context.getInputSplit(); // context获取split

               Path path = ((FileSplit) split).getPath(); // split获取文件路径

               fileNameKey = path.getName(); // 将文件路径实例化为key对象

               classNameKey = path.getParent().getName();

           }

     

           @Override// 实现map方法

           protectedvoid map(NullWritable key, BytesWritable value, Context context)

                  throws IOException, InterruptedException {

               // 注意sequencefilekeyvalue key:分类,文档名  value:文档的内容)

               context.write(new Text(classNameKey + "/" + fileNameKey), value);

           }

        }

    }

    4.2 WholeFileInputFormat.java 其中关键代码如下:

    publicclass WholeFileInputFormat extends FileInputFormat<NullWritable, BytesWritable> {

        /**

         * <p>方法描述:递归遍历输入目录下的所有文件</p>

         * <p>备注:该写FileInputFormat,使支持多层目录的输入</p>

         *  @authormeify DateTime 2015113下午2:37:49

         *  @param fs

         *  @param path

         */

        void search(FileSystem fs, Path path) {

           try {

               if (fs.isFile(path)) {

                  fileStatus.add(fs.getFileStatus(path));

               } elseif (fs.isDirectory(path)) {

                  FileStatus[] fileStatus = fs.listStatus(path);

                  for (inti = 0; i < fileStatus.lengthi++) {

                      FileStatus fileStatu = fileStatus[i];

                      search(fsfileStatu.getPath());

                  }

               }

           } catch (IOException e) {

               e.printStackTrace();

           }

        }

        @Override

        public RecordReader<NullWritable, BytesWritable> createRecordReader(InputSplit split, TaskAttemptContext context)

               throws IOException, InterruptedException {

           WholeFileRecordReader reader = new WholeFileRecordReader();

           reader.initialize(splitcontext);

           returnreader;

        }

        @Override

        protected List<FileStatus> listStatus(JobContext jobthrows IOException {

          

           FileSystem fs = FileSystem.get(job.getConfiguration());

           // 输入根目录

           String rootDir = job.getConfiguration().get("mapred.input.dir""");

           // 递归获取输入目录下的所有文件

           search(fsnew Path(rootDir));

           returnthis.fileStatus;

        }

    }

    4.3 WholeFileRecordReader.java 其中关键代码如下:

    publicclass WholeFileRecordReader extends RecordReader<NullWritable, BytesWritable>{

     

        private FileSplit fileSplit//保存输入的分片,它将被转换成一条( key value)记录

        private Configuration conf//配置对象

        private BytesWritable value = new BytesWritable(); //value对象,内容为空

        privatebooleanprocessed = false//布尔变量记录记录是否被处理过

        @Override

        publicboolean nextKeyValue() throws IOException, InterruptedException {

           if (!processed) { //如果记录没有被处理过

               //fileSplit对象获取split的字节数,创建byte数组contents

               byte[] contents = newbyte[(intfileSplit.getLength()];

               Path file = fileSplit.getPath(); //fileSplit对象获取输入文件路径

               FileSystem fs = file.getFileSystem(conf); //获取文件系统对象

               FSDataInputStream in = null//定义文件输入流对象

               try {

                  in = fs.open(file); //打开文件,返回文件输入流对象

    //从输入流读取所有字节到contents

                  IOUtils.readFully(incontents, 0, contents.length);          value.set(contents, 0, contents.length); //contens内容设置到value对象中

               } finally {

                  IOUtils.closeStream(in); //关闭输入流

               }

              

               processed = true//将是否处理标志设为true,下次调用该方法会返回false

               returntrue;

           }

               returnfalse//如果记录处理过,返回false,表示split处理完毕

        }

    }

    4.4 DocCount.java  其中MapReduce关键代码如下:

    publicclass DocCount extends Configured implements Tool{

     

        publicstaticclass Map extends Mapper<Text, BytesWritable, Text, IntWritable> {

           @Override

           publicvoid map(Text key, BytesWritable value, Context context) {

               try {

                  String currentKey = key.toString();

                  String[] arr = currentKey.split("/");

                  String className = arr[0];

                  String fileName = arr[1];

                  System.out.println(className + "," + fileName);

                  context.write(new Text(className), new IntWritable(1));

               } catch (IOException e) {

                  e.printStackTrace();

               } catch (InterruptedException e) {

                  e.printStackTrace();

               }

           }

        }

       

        publicstaticclass Reduce extends Reducer<Text, IntWritable, Text, IntWritable> {

           private IntWritable result = new IntWritable();

           publicvoid reduce(Text key, Iterable<IntWritable> values, Context contextthrows IOException, InterruptedException {

               intsum = 0;

               for (IntWritable val : values) {

                  sum ++;

               }

               result.set(sum);

               context.write(keyresult);  // 输出结果key: 分类 ,  value: 文档个数

           }

        }

    }

    4.5 WordCount.java  其中MapReduce关键代码如下:

    publicclass WordCount extends Configured implements Tool{

     

        publicstaticclass Map extends Mapper<Text, BytesWritable, Text, IntWritable> {

     

           @Override

           publicvoid map(Text key, BytesWritable value, Context context) {

               try {

                 

                  String[] arr = key.toString().split("/");

                  String className = arr[0];

                  String fileName = arr[1];

                  value.setCapacity(value.getSize()); // 剔除多余空间

                  // 文本内容

                   String content = new String(value.getBytes(), 0, value.getLength());

                  StringTokenizer itr = new StringTokenizer(content);

                  while (itr.hasMoreTokens()) {

                      String word = itr.nextToken();

                      if(StringUtil.isValidWord(word))

                      {

                         System.out.println(className + "/" + word);

                         context.write(new Text(className + "/" + word), new IntWritable(1));

                      }

                  }

               } catch (IOException e) {

                  e.printStackTrace();

               } catch (InterruptedException e) {

                  e.printStackTrace();

               }

           }

        }

       

        publicstaticclass Reduce extends Reducer<Text, IntWritable, Text, IntWritable> {

           private IntWritable result = new IntWritable();

           publicvoid reduce(Text key, Iterable<IntWritable> values, Context contextthrows IOException, InterruptedException {

               intsum = 1; // 注意这里单词的个数从1开始计数

               for (IntWritable val : values) {

                  sum ++;

               }

               result.set(sum);

               context.write(keyresult);  // 输出结果key: 分类单词 ,  value: 频次

           }

        }

    }

    4.6 DocClassification.java 其中MapReduce关键代码如下:

    publicclass DocClassification extends Configured implements Tool {

        // 所有分类集合

        privatestatic List<String> classList = new ArrayList<String>();

        // 所有分类的先验概率(其中的概率取对数log

        privatestatic HashMap<String, Double> classProMap = new HashMap<String, Double>();

        // 所有单词在各个分类中的出现的频次

        privatestatic HashMap<String, Integer> classWordNumMap = new HashMap<String, Integer>();

        // 分类下的所有单词出现的总频次

        privatestatic HashMap<String, Integer> classWordSumMap = new HashMap<String, Integer>();

        privatestatic Configuration conf = new Configuration();

        static {

           // 初始化分类先验概率词典

           initClassProMap("hdfs://192.168.226.129:9000/user/hadoop/doc");

           // 初始化单词在各个分类中的条件概率词典

           initClassWordProMap("hdfs://192.168.226.129:9000/user/hadoop/word");

        }

       

        publicstaticclass Map extends Mapper<Text, BytesWritable, Text, Text> {

           @Override

           publicvoid map(Text key, BytesWritable value, Context context) {

               String fileName = key.toString();

               value.setCapacity(value.getSize()); // 剔除多余空间

               String content = new String(value.getBytes(), 0, value.getLength());

               try {

                  for (String className : classList) {

                      doubleresult = Math.log(classProMap.get(className));

                      StringTokenizer itr = new StringTokenizer(content);

                      while (itr.hasMoreTokens()) {

                         String word = itr.nextToken();

                         if (StringUtil.isValidWord(word)) {

                             intwordSum = 1;

                             if(classWordNumMap.get(className + "/" + word) != null){

                                wordSum = classWordNumMap.get(className + "/" + word);

                             }

                             intclassWordSum = classWordSumMap.get(className);

                             doublepro_class_word = Math.log(((double)wordSum)/classWordSum);

                             result += pro_class_word;

                         }

                      }

                      // 输出的形式 key:文件名 value:分类名/概率

                      context.write(new Text(fileName), new Text(className + "/" + String.valueOf(result)));

                  }

               } catch (IOException e) {

                  e.printStackTrace();

               } catch (InterruptedException e) {

                  e.printStackTrace();

               }

           }

        }

     

        publicstaticclass Reduce extends Reducer<Text, Text, Text, Text> {

     

           publicvoid reduce(Text key, Iterable<Text> values, Context contextthrows IOException, InterruptedException {

               String fileName = key.toString().split("/")[1];

        doublemaxPro = Math.log(Double.MIN_VALUE);

               String maxClassName = "unknown";

               for (Text value : values) {

                  String[] arr = value.toString().split("/");

                  String className = arr[0];

                  doublepro = Double.valueOf(arr[1]);

                  if (pro > maxPro) {

                      maxPro = pro;

                      maxClassName = className;

                  }

               }

               System.out.println("fileName:" + fileName + ",belong class:" + maxClassName);

               // 输出 key:文件名 value:所属分类名以及概率

               context.write(new Text(fileName), new Text(maxClassName + ",pro=" + maxPro));

           }

        }

    }

    四、数据集说明

    训练集:CHINA  文档数255

    INDIA   文档数326

    TAIWAN  文档数43.

    测试集:CHINA   文档个数15

    INDIA    文档个数20

    TAIWAN  文档个数15

    1. 程序运行说明

    5.1训练数据集打包程序

    Map任务个数624(所有小文件的个数)   Reduce任务个数1

    截图如下

     

    5.2训练文档统计程序

    Map任务个数1(输入为1SequencedFile   Reduce任务个数1

    5.3训练单词统计程序

    Map任务个数1(输入为1SequencedFile)   Reduce任务个数1

    5.4测试数据集打包程序

    Map任务个数50(测试数据集小文件个数为50)   Reduce任务个数1

    5.5测试文档归类程序

    Map任务个数1(输入为1SequencedFile   Reduce任务个数1

     

    1. 实验结果分析

    测试集文档归类结果截图如下:

     针对CHINA TAIWAN INDIA三个分类下的测试文档进行测试结果如下表所示:

    类别(国家)

    正确率

    召回率

    F1

    CHINA

    18.4%

    46.667%

    26.38%

    INDIA

    42.1%

    80%

    55.67%

    TAIWAN

    39.47%

    100%

    56.60%

    展开全文
    kuailefangyuan 2016-11-18 17:26:30
  • 基于朴素贝叶斯分类器文本分类算法(C语言)基于朴素贝叶斯分类器文本分类算法(C语言).txt两个人吵架,先说对不起的人,并不是认输了,并不是原谅了。他只是比对方更珍惜这份感情。#include #include #include //_...

    基于朴素贝叶斯分类器的文本分类算法(C语言)

    基于朴素贝叶斯分类器的文本分类算法(C语言).txt两个人吵架,先说对不起的人,并不是认输了,并不是原谅了。他只是比对方更珍惜这份感情。#include

    #include

    #include //_getcwd(), _chdir()

    #include //_MAX_PATH, system()

    #include //_finddata_t, _findfirst(), _findnext(), _findclose()

    char vocabulary[1000][20];/*声明公有二维数组,用来存储分割好的单词*/

    /*=================将要分类的文本分割成单词存储在二维数组vocabulary中================*/

    //@输入参数:要分类的文本

    //@输出参数:该文本中总单词数

    int SplitToWord(char text[])

    {

    int i=0;

    char seps[]=", .\n"; /*定义单词的分隔符*/

    char *substring;

    /******利用分隔符将文本内容分割成单词并存储******/

    substring=strtok(text,seps);

    while(substring!=NULL)

    {

    strcpy(vocabulary[i],substring);//将单词存储到vocabulary数组中

    substring=strtok(NULL,seps);

    i++;

    }

    return i; //返回一共多少个单词

    }

    /*===============================计算该目录下的文件数================================*/

    //@输入参数:无

    //@输出参数:该目录下.txt文件数

    int CountDirectory()

    {

    int count=0; //txt文件计数器

    long hFile;

    AAAAAA

    展开全文
    weixin_29553791 2021-06-07 05:22:10
  • 4星
    14KB baidu_14912731 2017-03-30 11:04:20
  • 107KB m0_52957036 2020-08-09 00:10:57
  • 3星
    1.59MB sinat_23187055 2017-04-25 18:57:58
  • 基于朴素贝叶斯分类器文本分类算法(上) http://www.cnblogs.com/phinecos/archive/2008/10/21/1316044.html 基于朴素贝叶斯分类器文本分类算法(下) ... ...作者:phi

    基于朴素贝叶斯分类器的文本分类算法(上)

    http://www.cnblogs.com/phinecos/archive/2008/10/21/1316044.html

    基于朴素贝叶斯分类器的文本分类算法(下)

    http://www.cnblogs.com/phinecos/archive/2008/10/21/1316044.html


    转载请保留作者信息:

    作者:phinecos(洞庭散人)

    Bloghttp://phinecos.cnblogs.com/

    Emailphinecos@163.com

     Preface

           本文缘起于最近在读的一本书-- Tom M.Mitchell《机器学习》,书中第6章详细讲解了贝叶斯学习的理论知识,为了将其应用到实际中来,参考了网上许多资料,从而得此文。文章将分为两个部分,第一部分将介绍贝叶斯学习的相关理论(如果你对理论不感兴趣,请直接跳至第二部分<<基于朴素贝叶斯分类器的文本分类算法(下)>>)。第二部分讲如何将贝叶斯分类器应用到中文文本分类,随文附上示例代码。

     Introduction

    我们在《概率论和数理统计》这门课的第一章都学过贝叶斯公式和全概率公式,先来简单复习下:

    条件概率

    定义 A, B是两个事件,且P(A)>0 P(BA)=P(AB)/P(A)为在条件A下发生的条件事件B发生的条件概率。

    乘法公式 P(A)>0 则有P(AB)=P(BA)P(A)

    全概率公式和贝叶斯公式

    定义 S为试验E的样本空间,B1, B2, …BnE的一组事件,若BiBj=Ф, i≠j, i, j=1, 2, …,n; B1B2Bn=S则称B1, B2, …, Bn为样本空间的一个划分。

    定理 设试验E的样本空间为,AE的事件,B1, B2, …,Bn为的一个划分,且P(Bi)>0 (i=1, 2, …n),则P(A)=P(AB1)P(B1)+P(AB2)+ …+P(ABn)P(Bn)称为全概率公式。

    定理 设试验俄E的样本空间为SAE的事件,B1, B2, …,Bn为的一个划分,则

    P(BiA)=P(ABi)P(Bi)/∑P(BAj)P(Aj)=P(BAi)P(Ai)/P(B)

    称为贝叶斯公式。说明:ij均为下标,求和均是1n  

     下面我再举个简单的例子来说明下。

    示例1

    考虑一个医疗诊断问题,有两种可能的假设:(1)病人有癌症。(2)病人无癌症。样本数据来自某化验测试,它也有两种可能的结果:阳性和阴性。假设我们已经有先验知识:在所有人口中只有0.008的人患病。此外,化验测试对有病的患者有98%的可能返回阳性结果,对无病患者有97%的可能返回阴性结果。

    上面的数据可以用以下概率式子表示:

    P(cancer)=0.008,P(cancer)=0.992

    P(阳性|cancer)=0.98,P(阴性|cancer)=0.02

    P(阳性|cancer)=0.03P(阴性|cancer)=0.97

    假设现在有一个新病人,化验测试返回阳性,是否将病人断定为有癌症呢?我们可以来计算极大后验假设:

    P(阳性|cancer)p(cancer)=0.98*0.008 = 0.0078

    P(阳性|cancer)*p(cancer)=0.03*0.992 = 0.0298

    因此,应该判断为无癌症。

     贝叶斯学习理论

           贝叶斯是一种基于概率的学习算法,能够用来计算显式的假设概率,它基于假设的先验概率,给定假设下观察到不同数据的概率以及观察到的数据本身(后面我们可以看到,其实就这么三点东西,呵呵)。

          我们用P(h)表示没有训练样本数据前假设h拥有的初始概率,也就称为h的先验概率,它反映了我们所拥有的关于h是一个正确假设的机会的背景知识。当然如果没有这个先验知识的话,在实际处理中,我们可以简单地将每一种假设都赋给一个相同的概率。类似,P(D)代表将要观察的训练样本数据D的先验概率(也就是说,在没有确定某一个假设成立时D的概率)。然后是P(D/h),它表示假设h成立时观察到数据D的概率。在机器学习中,我们感兴趣的是P(h/D),也就是给定了一个训练样本数据D,判断假设h成立的概率,这也称之为后验概率,它反映了在看到训练样本数据D后假设h成立的置信度。(注:后验概率p(h/D)反映了训练数据D的影响,而先验概率p(h)是独立于D的)。

     

    P(h|D) = P(D|h)P(h)/p(D),从贝叶斯公式可以看出,后验概率p(h/D)取决于P(D|h)P(h)这个乘积,呵呵,这就是贝叶斯分类算法的核心思想。我们要做的就是要考虑候选假设集合H,并在其中寻找当给定训练数据D时可能性最大的假设hh属于H)。

          简单点说,就是给定了一个训练样本数据(样本数据已经人工分类好了),我们应该如何从这个样本数据集去学习,从而当我们碰到新的数据时,可以将新数据分类到某一个类别中去。那可以看到,上面的贝叶斯理论和这个任务是吻合的。

    朴素贝叶斯分类

     

    也许你觉得这理论还不是很懂,那我再举个简单的例子,让大家对这个算法的原理有个快速的认识。(注:这个示例摘抄自《机器学习》这本书的第三章的表3-2.

    假设给定了如下训练样本数据,我们学习的目标是根据给定的天气状况判断你对PlayTennis这个请求的回答是Yes还是No

    Day

    Outlook

    Temperature

    Humidity

    Wind

    PlayTennis

    D1

    Sunny

    Hot

    High

    Weak

    No

    D2

    Sunny

    Hot

    High

    Strong

    No

    D3

    Overcast

    Hot

    High

    Weak

    Yes

    D4

    Rain

    Mild

    High

    Weak

    Yes

    D5

    Rain

    Cool

    Normal

    Weak

    Yes

    D6

    Rain

    Cool

    Normal

    Strong

    No

    D7

    Overcast

    Cool

    Normal

    Strong

    Yes

    D8

    Sunny

    Mild

    High

    Weak

    No

    D9

    Sunny

    Cool

    Normal

    Weak

    Yes

    D10

    Rain

    Mild

    Normal

    Weak

    Yes

    D11

    Sunny

    Mild

    Normal

    Strong

    Yes

    D12

    Overcast

    Mild

    High

    Strong

    Yes

    D13

    Overcast

    Hot

    Normal

    Weak

    Yes

    D14

    Rain

    Mild

    High

    Strong

    No

     可以看到这里样本数据集提供了14个训练样本,我们将使用此表的数据,并结合朴素贝叶斯分类器来分类下面的新实例:

    (Outlook = sunny,Temprature = cool,Humidity = high,Wind = strong)

    我们的任务就是对此新实例预测目标概念PlayTennis的目标值(yesno).

    由上面的公式可以得到:

    可以得到:

          P(PlayTennis =yes) = 9/14 = 0.64,P(PlayTennis=no)=5/14 = 0.36

          P(Wind=Stong| PlayTennis =yes)=3/9=0.33,p(Wind=Stong| PlayTennis =no)=3/5 = 0.6

    其他数据类似可得,代入后得到:

    P(yes)P(Sunny|yes)P(Cool|yes)P(high|yes)P(Strong|yes) = 0.0053

    P(no)P(Sunny|no)P(Cool|no)P(high|no)P(Strong|no)=0.0206

    因此应该分类到no这一类中。

     

    贝叶斯文本分类算法

          好了,现在开始进入本文的主旨部分:如何将贝叶斯分类器应用到中文文本的分类上来?

    根据联合概率公式(全概率公式)

     

    M——训练文本集合中经过踢出无用词去除文本预处理之后关键字的数量。

    作者:洞庭散人

    出处:http://phinecos.cnblogs.com/    

    本博客遵从 Creative Commons Attribution 3.0 License ,若用于非商业目的,您可以自由转载,但请保留原作者信息和文章链接URL。



    源代码下载:NaviveBayesClassify.rar 

    Preface

    文本的分类和聚类是一个比较有意思的话题,我以前也写过一篇blog基于K-Means的文本聚类算法》,加上最近读了几本数据挖掘和机器学习的书籍,因此很想写点东西来记录下学习的所得。

    在本文的上半部分《基于朴素贝叶斯分类器的文本分类算法(上)》一文中简单介绍了贝叶斯学习的基本理论,这一篇将展示如何将该理论运用到中文文本分类中来,具体的文本分类原理就不再介绍了,在上半部分有,也可以参见代码的注释。

    文本特征向量

    文本特征向量可以描述为文本中的字/词构成的属性。例如给出文本:

    Good good study,Day day up.

    可以获得该文本的特征向量集:{ Good, good, study, Day, day , up.}

    朴素贝叶斯模型是文本分类模型中的一种简单但性能优越的的分类模型。为了简化计算过程,假定各待分类文本特征变量是相互独立的,即朴素贝叶斯模型的假设。相互独立表明了所有特征变量之间的表述是没有关联的。如上例中,[good][study]这两个特征变量就是没有任何关联的。

    在上例中,文本是英文,但由于中文本身是没有自然分割符(如空格之类符号),所以要获得中文文本的特征变量向量首先需要对文本进行中文分词

    中文分词

          这里采用极易中文分词组件,这个中文分词组件可以免费使用,提供Lucene接口,跨平台,性能可靠。

    复制代码
    package com.vista;
    import java.io.IOException;      
    import jeasy.analysis.MMAnalyzer;

    /* *
    * 中文分词器
    */
    public   class  ChineseSpliter 
    {
        
    /* *
        * 对给定的文本进行中文分词
        * @param text 给定的文本
        * @param splitToken 用于分割的标记,如"|"
        * @return 分词完毕的文本
        
    */
        
    public   static  String split(String text,String splitToken)
        {
            String result 
    =   null ;
            MMAnalyzer analyzer 
    =   new  MMAnalyzer();      
            
    try       
            {
                result 
    =  analyzer.segment(text, splitToken);    
            }      
            
    catch  (IOException e)      
            {     
                e.printStackTrace();     
            }     
            
    return  result;
        }
    }
    复制代码

    停用词处理

          去掉文档中无意思的词语也是必须的一项工作,这里简单的定义了一些常见的停用词,并根据这些常用停用词在分词时进行判断。

    复制代码
    package com.vista;

    /* *
    * 停用词处理器
    * @author phinecos 

    */
    public   class  StopWordsHandler 
    {
        
    private   static  String stopWordsList[]  = { " " " 我们 " , " " , " 自己 " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , " " , "" }; // 常用停用词
         public   static  boolean IsStopWord(String word)
        {
            
    for ( int  i = 0 ;i < stopWordsList.length; ++ i)
            {
                
    if (word.equalsIgnoreCase(stopWordsList[i]))
                    
    return   true ;
            }
            
    return   false ;
        }
    }
    复制代码

    训练集管理器

          我们的系统首先需要从训练样本集中得到假设的先验概率和给定假设下观察到不同数据的概率。

    复制代码
    package  com.vista;
    import  java.io.BufferedReader;
    import  java.io.File;
    import  java.io.FileInputStream;
    import  java.io.FileNotFoundException;
    import  java.io.IOException;
    import  java.io.InputStreamReader;
    import  java.util.Properties;
    import  java.util.logging.Level;
    import  java.util.logging.Logger;
    /**
    * 训练集管理器
    */
    public   class  TrainingDataManager 
    {
        
    private  String[] traningFileClassifications; // 训练语料分类集合
         private  File traningTextDir; // 训练语料存放目录
         private   static  String defaultPath  =   " D:\\TrainningSet " ;
        
        
    public  TrainingDataManager() 
        {
            traningTextDir 
    =   new  File(defaultPath);
            
    if  ( ! traningTextDir.isDirectory()) 
            {
                
    throw   new  IllegalArgumentException( " 训练语料库搜索失败! [ "   + defaultPath  +   " ] " );
            }
            
    this .traningFileClassifications  =  traningTextDir.list();
        }
        
    /**
        * 返回训练文本类别,这个类别就是目录名
        * 
    @return  训练文本类别
        
    */
        
    public  String[] getTraningClassifications() 
        {
            
    return   this .traningFileClassifications;
        }
        
    /**
        * 根据训练文本类别返回这个类别下的所有训练文本路径(full path)
        * 
    @param  classification 给定的分类
        * 
    @return  给定分类下所有文件的路径(full path)
        
    */
        
    public  String[] getFilesPath(String classification) 
        {
            File classDir 
    =   new  File(traningTextDir.getPath()  + File.separator  + classification);
            String[] ret 
    =  classDir.list();
            
    for  ( int  i  =   0 ; i  <  ret.length; i ++
            {
                ret[i] 
    =  traningTextDir.getPath()  + File.separator  + classification  + File.separator  + ret[i];
            }
            
    return  ret;
        }
        
    /**
        * 返回给定路径的文本文件内容
        * 
    @param  filePath 给定的文本文件路径
        * 
    @return  文本内容
        * 
    @throws  java.io.FileNotFoundException
        * 
    @throws  java.io.IOException
        
    */
        
    public   static  String getText(String filePath)  throws  FileNotFoundException,IOException 
        {
            InputStreamReader isReader 
    = new  InputStreamReader( new  FileInputStream(filePath), " GBK " );
            BufferedReader reader 
    =   new  BufferedReader(isReader);
            String aline;
            StringBuilder sb 
    =   new  StringBuilder();
            
    while  ((aline  =  reader.readLine())  !=   null )
            {
                sb.append(aline 
    +   "   " );
            }
            isReader.close();
            reader.close();
            
    return  sb.toString();
        }
        
    /**
        * 返回训练文本集中所有的文本数目
        * 
    @return  训练文本集中所有的文本数目
        
    */
        
    public   int  getTrainingFileCount()
        {
            
    int  ret  =   0 ;
            
    for  ( int  i  =   0 ; i  <  traningFileClassifications.length; i ++ )
            {
                ret 
    += getTrainingFileCountOfClassification(traningFileClassifications[i]);
            }
            
    return  ret;
        }
        
    /**
        * 返回训练文本集中在给定分类下的训练文本数目
        * 
    @param  classification 给定的分类
        * 
    @return  训练文本集中在给定分类下的训练文本数目
        
    */
        
    public   int  getTrainingFileCountOfClassification(String classification)
        {
            File classDir 
    =   new  File(traningTextDir.getPath()  + File.separator  + classification);
            
    return  classDir.list().length;
        }
        
    /**
        * 返回给定分类中包含关键字/词的训练文本的数目
        * 
    @param  classification 给定的分类
        * 
    @param  key 给定的关键字/词
        * 
    @return  给定分类中包含关键字/词的训练文本的数目
        
    */
        
    public   int  getCountContainKeyOfClassification(String classification,String key) 
        {
            
    int  ret  =   0 ;
            
    try  
            {
                String[] filePath 
    =  getFilesPath(classification);
                
    for  ( int  j  =   0 ; j  <  filePath.length; j ++
                {
                    String text 
    =  getText(filePath[j]);
                    
    if  (text.contains(key)) 
                    {
                        ret
    ++ ;
                    }
                }
            }
            
    catch  (FileNotFoundException ex) 
            {
            Logger.getLogger(TrainingDataManager.
    class .getName()).log(Level.SEVERE,  null ,ex);
        
            } 
            
    catch  (IOException ex)
            {
                Logger.getLogger(TrainingDataManager.
    class .getName()).log(Level.SEVERE,  null ,ex);
            }
            
    return  ret;
        }
    }
    复制代码

    先验概率

          先验概率是我们需要计算的两大概率值之一

    复制代码
    package  com.vista;
    /**
    * 先验概率计算
    * <h3>先验概率计算</h3>
    * P(c<sub>j</sub>)=N(C=c<sub>j</sub>)<b>/</b>N <br>
    * 其中,N(C=c<sub>j</sub>)表示类别c<sub>j</sub>中的训练文本数量;
    * N表示训练文本集总数量。
    */
    public   class  PriorProbability 
    {
        
    private   static  TrainingDataManager tdm  = new  TrainingDataManager();
        
    /**
        * 先验概率
        * 
    @param  c 给定的分类
        * 
    @return  给定条件下的先验概率
        
    */
        
    public   static   float  calculatePc(String c)
        {
            
    float  ret  =  0F;
            
    float  Nc  =  tdm.getTrainingFileCountOfClassification(c);
            
    float  N  =  tdm.getTrainingFileCount();
            ret 
    =  Nc  /  N;
            
    return  ret;
        }
    }

    复制代码

    分类条件概率

          这是另一个影响因子,和先验概率一起来决定最终结果

    复制代码
    package  com.vista;

    /**
    * <b>类</b>条件概率计算
    *
    * <h3>类条件概率</h3>
    * P(x<sub>j</sub>|c<sub>j</sub>)=( N(X=x<sub>i</sub>, C=c<sub>j
    * </sub>)+1 ) <b>/</b> ( N(C=c<sub>j</sub>)+M+V ) <br>
    * 其中,N(X=x<sub>i</sub>, C=c<sub>j</sub>)表示类别c<sub>j</sub>中包含属性x<sub>
    * i</sub>的训练文本数量;N(C=c<sub>j</sub>)表示类别c<sub>j</sub>中的训练文本数量;M值用于避免
    * N(X=x<sub>i</sub>, C=c<sub>j</sub>)过小所引发的问题;V表示类别的总数。
    *
    * <h3>条件概率</h3>
    * <b>定义</b> 设A, B是两个事件,且P(A)>0 称<br>
    * <tt>P(B∣A)=P(AB)/P(A)</tt><br>
    * 为在条件A下发生的条件事件B发生的条件概率。

    */

    public   class  ClassConditionalProbability 
    {
        
    private   static  TrainingDataManager tdm  =   new  TrainingDataManager();
        
    private   static   final   float  M  =  0F;
        
        
    /**
        * 计算类条件概率
        * 
    @param  x 给定的文本属性
        * 
    @param  c 给定的分类
        * 
    @return  给定条件下的类条件概率
        
    */
        
    public   static   float  calculatePxc(String x, String c) 
        {
            
    float  ret  =  0F;
            
    float  Nxc  =  tdm.getCountContainKeyOfClassification(c, x);
            
    float  Nc  =  tdm.getTrainingFileCountOfClassification(c);
            
    float  V  =  tdm.getTraningClassifications().length;
            ret 
    =  (Nxc  +   1 /  (Nc  +  M  +  V);  // 为了避免出现0这样极端情况,进行加权处理
             return  ret;
        }
    }
    复制代码

    分类结果

          用来保存各个分类及其计算出的概率值,

    复制代码
    package  com.vista;
    /**
    * 分类结果
    */
    public   class  ClassifyResult 
    {
        
    public   double  probility; // 分类的概率
         public  String classification; // 分类
         public  ClassifyResult()
        {
            
    this .probility  =   0 ;
            
    this .classification  =   null ;
        }
    }
    复制代码

    朴素贝叶斯分类器

          利用样本数据集计算先验概率和各个文本向量属性在分类中的条件概率,从而计算出各个概率值,最后对各个概率值进行排序,选出最大的概率值,即为所属的分类。

    复制代码
    package  com.vista;
    import  com.vista.ChineseSpliter;
    import  com.vista.ClassConditionalProbability;
    import  com.vista.PriorProbability;
    import  com.vista.TrainingDataManager;
    import  com.vista.StopWordsHandler;
    import  java.util.ArrayList;
    import  java.util.Comparator;
    import  java.util.List;
    import  java.util.Vector;

    /**
    * 朴素贝叶斯分类器
    */
    public   class  BayesClassifier 
    {
        
    private  TrainingDataManager tdm; // 训练集管理器
         private  String trainnigDataPath; // 训练集路径
         private   static   double  zoomFactor  =   10.0f ;
        
    /**
        * 默认的构造器,初始化训练集
        
    */
        
    public  BayesClassifier() 
        {
            tdm 
    = new  TrainingDataManager();
        }

        
    /**
        * 计算给定的文本属性向量X在给定的分类Cj中的类条件概率
        * <code>ClassConditionalProbability</code>连乘值
        * 
    @param  X 给定的文本属性向量
        * 
    @param  Cj 给定的类别
        * 
    @return  分类条件概率连乘值,即<br>
        
    */
        
    float  calcProd(String[] X, String Cj) 
        {
            
    float  ret  =   1.0F ;
            
    //  类条件概率连乘
             for  ( int  i  =   0 ; i  < X.length; i ++ )
            {
                String Xi 
    =  X[i];
                
    // 因为结果过小,因此在连乘之前放大10倍,这对最终结果并无影响,因为我们只是比较概率大小而已
                ret  *= ClassConditionalProbability.calculatePxc(Xi, Cj) * zoomFactor;
            }
            
    //  再乘以先验概率
            ret  *=  PriorProbability.calculatePc(Cj);
            
    return  ret;
        }
        
    /**
        * 去掉停用词
        * 
    @param  text 给定的文本
        * 
    @return  去停用词后结果
        
    */
        
    public  String[] DropStopWords(String[] oldWords)
        {
            Vector
    < String >  v1  =   new  Vector < String > ();
            
    for ( int  i = 0 ;i < oldWords.length; ++ i)
            {
                
    if (StopWordsHandler.IsStopWord(oldWords[i]) == false )
                {
    // 不是停用词
                    v1.add(oldWords[i]);
                }
            }
            String[] newWords 
    =   new  String[v1.size()];
            v1.toArray(newWords);
            
    return  newWords;
        }
        
    /**
        * 对给定的文本进行分类
        * 
    @param  text 给定的文本
        * 
    @return  分类结果
        
    */
        @SuppressWarnings(
    " unchecked " )
        
    public  String classify(String text) 
        {
            String[] terms 
    =   null ;
            terms
    =  ChineseSpliter.split(text,  "   " ).split( "   " ); // 中文分词处理(分词后结果可能还包含有停用词)
            terms  =  DropStopWords(terms); // 去掉停用词,以免影响分类
            
            String[] Classes 
    =  tdm.getTraningClassifications(); // 分类
             float  probility  =   0.0F ;
            List
    < ClassifyResult >  crs  =   new  ArrayList < ClassifyResult > (); // 分类结果
             for  ( int  i  =   0 ; i  < Classes.length; i ++
            {
                String Ci 
    =  Classes[i]; // 第i个分类
                probility  =  calcProd(terms, Ci); // 计算给定的文本属性向量terms在给定的分类Ci中的分类条件概率
                
    // 保存分类结果
                ClassifyResult cr  =   new  ClassifyResult();
                cr.classification 
    =  Ci; // 分类
                cr.probility  =  probility; // 关键字在分类的条件概率
                System.out.println( " In process. " );
                System.out.println(Ci 
    +   " "   +  probility);
                crs.add(cr);
            }
            
    // 对最后概率结果进行排序
            java.util.Collections.sort(crs, new  Comparator() 
            {
                
    public   int  compare( final  Object o1, final  Object o2) 
                {
                    
    final  ClassifyResult m1  =  (ClassifyResult) o1;
                    
    final  ClassifyResult m2  =  (ClassifyResult) o2;
                    
    final   double  ret  =  m1.probility  -  m2.probility;
                    
    if  (ret  <   0
                    {
                        
    return   1 ;
                    } 
                    
    else  
                    {
                        
    return   - 1 ;
                    }
                }
            });
            
    // 返回概率最大的分类
             return  crs.get( 0 ).classification;
        }
        
        
    public   static   void  main(String[] args)
        {
            String text 
    =   " 微软公司提出以446亿美元的价格收购雅虎中国网2月1日报道 美联社消息,微软公司提出以446亿美元现金加股票的价格收购搜索网站雅虎公司。微软提出以每股31美元的价格收购雅虎。微软的收购报价较雅虎1月31日的收盘价19.18美元溢价62%。微软公司称雅虎公司的股东可以选择以现金或股票进行交易。微软和雅虎公司在2006年底和2007年初已在寻求双方合作。而近两年,雅虎一直处于困境:市场份额下滑、运营业绩不佳、股价大幅下跌。对于力图在互联网市场有所作为的微软来说,收购雅虎无疑是一条捷径,因为双方具有非常强的互补性。(小桥) " ;
            BayesClassifier classifier 
    =   new  BayesClassifier(); // 构造Bayes分类器
            String result  =  classifier.classify(text); // 进行分类
            System.out.println( " 此项属于[ " + result + " ] " );
        }
    }
    复制代码

    训练集与分类测试

    作为测试,这里选用Sogou实验室的文本分类数据,我只使用了mini版本。迷你版本有10个类别 ,共计100篇文章,总大小244KB

    使用的测试文本:

    复制代码
    微软公司提出以446亿美元的价格收购雅虎

    中国网2月1日报道 美联社消息,微软公司提出以446亿美元现金加股票的价格收购搜索网站雅虎公司。

    微软提出以每股31美元的价格收购雅虎。微软的收购报价较雅虎1月31日的收盘价19
    . 18美元溢价62%。微软公司称雅虎公司的股东可以选择以现金或股票进行交易。

    微软和雅虎公司在2006年底和2007年初已在寻求双方合作。而近两年,雅虎一直处于困境:市场份额下滑、运营业绩不佳、股价大幅下跌。对于力图在互联网市场有所作为的微软来说,收购雅虎无疑是一条捷径,因为双方具有非常强的互补性。
    ( 小桥 )
    复制代码

    使用mini版本的测试结果:

    复制代码
    In process .
    IT:
    2.8119528E-5
    In process
    .
    体育:
    2.791735E-21
    In process
    .
    健康:
    3.3188528E-12
    In process
    .
    军事:
    2.532662E-19
    In process
    .
    招聘:
    2.3753596E-17
    In process
    .
    教育:
    4.2023427E-19
    In process
    .
    文化:
    6.0595915E-23
    In process
    .
    旅游:
    5.1286412E-17
    In process
    .
    汽车:
    4.085446E-8
    In process
    .
    财经:
    3.7337095E-10
    此项属于[IT]
    复制代码

    作者:洞庭散人

    出处:http://phinecos.cnblogs.com/    

    本博客遵从 Creative Commons Attribution 3.0 License ,若用于非商业目的,您可以自由转载,但请保留原作者信息和文章链接URL。



    展开全文
    lostinai 2015-10-30 15:12:40
  • weixin_26720761 2020-09-05 09:20:03
  • weixin_43580339 2021-04-09 10:58:42
  • 65KB luohualiushui1 2019-02-06 18:28:30
  • 19KB weixin_42116604 2021-07-11 07:40:23

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,983
精华内容 4,793
关键字:

朴素贝叶斯分类器进行文本分类