作者:白宁超

2015年9月29日11:10:02  

摘要当前数据挖掘技术使用最为广泛的莫过于文本挖掘领域,包括领域本体构建、短文本实体抽取以及代码的语义级构件方法研究。常用的数据挖掘功能包括分类、聚类、预测和关联四大模型。本文针对四大模型之一的分类进行讨论。分类算法包括回归、决策树、支持向量机、贝叶斯等,显然,不少涉及机器学习的知识(随后会写些机器学习专题)。本文重点介绍贝叶斯分类,涉及朴素贝叶斯模型、二项独立模型、多项模型、混合模型等知识。在本人研究贝叶斯分类过程中,发现很多博客重复现象严重,并且在构建模型过程中存在大量的问题。包括博客园中最受欢迎的几篇,整个模型构造就不符合理论。索性自己重新查阅外文文献,进而得到很大帮助。本文针对几种模型,采用算法概述、算法公式解析、公式推理、优缺点比较等进行总结。(本文原创,转载注明出处: 多种贝叶斯模型构建及文本分类的实现

相关文章


【文本处理】自然语言处理在现实生活中运用

【文本处理】多种贝叶斯模型构建及文本分类的实现

【文本处理】快速了解什么是自然语言处理

【文本处理】领域本体构建方法概述

【文本挖掘(1)】OpenNLP:驾驭文本,分词那些事

【文本挖掘(2)】【NLP】Tika 文本预处理:抽取各种格式文件内容

【文本挖掘(3)】自己动手搭建搜索工具

0 引言


     于半月前,针对文本分类进行学习,实验的目的是通过对下图1中的不同情感文本构建训练集模型,对应的下图2是对训练集的注释说明。类标0开头为喜悦类别,类标1开头的为愤怒类别,类别2开头的是厌恶类别,类别3开头的为低落类别。4个训练集文本,分别对应4个分类。如何通过训练集构造分类器,并对测试数据进行验证是本课题的最终目的。其中会涉及贝叶斯公式的理解与实现,文本的预处理(下图1中0_simplifyweibo的训练集是处理过的数据如下图),分词工具的使用,不同贝叶斯模型的构造,试验结果对比。核心思路就两点:1,模型训练阶段  2,分类预测阶段。完整流程如下:

-->训练文本预处理,构造分类器。(即对贝叶斯公式实现文本分类参数值的求解,暂时不理解没关系,下文详解

-->构造预测分类函数

-->对测试数据预处理

-->使用分类器分类

                 贝叶斯模型构建分类器的设计与实现贝叶斯模型构建分类器的设计与实现      

1 四种模型结构


  • 朴素贝叶斯模型     NaiveBayes model                                 NM
  • 二项独立模型        Bnary independence model                     BIM
  • 多项式模型           multinomial model                                  MM
  • 混合模型              hyorid   model                                        HM
  • 平滑因子混合模型   hyorid model with new smooth factore     HM&NSF 

2 朴素贝叶斯分类器


  • 思想概述

-- 公式 P( Category | Document) = (P ( Document | Category ) * P( Category))/ P(Document)
-- 朴素贝叶斯分类器: P(c|d)~=P(c)*P(d|c)
-- 训练阶段:对每一个W_k,C_i估计先验条件概率P(w_k|c_i)和概率P(C_i)
-- 分类阶段:计算后验概率,返回使后验概率最大的类
-- C(d)=argmax {P(C_i)*P(d|c_i)

    对于一个新的训练文档d,究竟属于如上四个类别的哪个类别?我们可以根据贝叶斯公式,只是此刻变化成具体的对象。 

> P( Category | Document):测试文档属于某类的概率

> P( Category)):从文档空间中随机抽取一个文档d,它属于类别c的概率。(某类文档数目/总文档数目

> (P ( Document | Category ):文档d对于给定类c的概率(某类下文档中单词数/某类中总的单词数

> P(Document):从文档空间中随机抽取一个文档d的概率(对于每个类别都一样,可以忽略不计算。此时为求最大似然概率

>  C(d)=argmax {P(C_i)*P(d|c_i)}:求出近似的贝叶斯每个类别的概率,比较获取最大的概率,此时文档归为最大概率的一类,分类成功。

综上:对训练集构成训练分类器模型的过程,本质是对参数模型的求解。然后将这些参数在预测方法中使用,根据公式获取最大概率即可完成文档分类。

  • 公式推导与解析

朴素贝叶斯公式:(假设条件:当文档d属于类c时,文档d中的元素w的取值与类c中的w的取值是独立关系[实际显示不独立,一种近似处理])

 贝叶斯模型构建分类器的设计与实现

公式解析:

> P(d):从文档空间中随机抽取一个文档d的概率(对于每个类别都一样,可以忽略不计算。此时为求最大似然概率)   

> P(c):从文档空间中随机抽取一个文档d,它属于类别c的概率。(某类文档数目/总文档数目)

> (P ( d| c ):文档d对于给定类c的概率(某类下文档中单词数/某类中总的单词数)

> 类别集: c={c1,c2,.....,cn}

> 文档向量: d={w1,w2,.....,wn} 

> 类别集: c={c1,c2,.....,cn}

> P(c| d):测试文档d属于某类c的概率(估计条件概率)【估计概率:训练集中进行训练过程,在某种假设条件下实现的】

> MaxP(c| d):测试文档d属于某类c的最大概率

先验条件概率:

 贝叶斯模型构建分类器的设计与实现

将(2)式代入(1)得:(下式中p(d)对于所有的类c都是一样的)

 贝叶斯模型构建分类器的设计与实现

注:只要对上式中的分母求出最大值即可。分母中的左部分通过(某类文档数目/总文档数目)易得,右侧中通过求文档d和c中单词量即可。到此,解决思路和思想都有了,下面基于此完成算法。

  • 算法介绍与实现

算法1:文本分类的朴素贝叶斯算法


训练阶段:对每一个w_k,c_i估计先验条件概率p(w_k|c_i)和概率p(c_i)。

分类阶段:计算后验概率,返回使后验概率最大的类。

  贝叶斯模型构建分类器的设计与实现


算法具体实现:

    /**
     * 朴素贝叶斯文本分类器
     * 训练阶段
     * 算法思想:文档d属于某类c的概率=文档空间随机抽取一个文档d属于某类c的概率*文档中的单词与总单词的比例
     *        P(c|d)~=P(c)*P(d|c)
     *        P(c)=classDocnum/classAlldocnum
     * 计算参数:
     *       classDocnum:某类中的文档数目
     *       classAlldocnum:数据集中总的文档数目
     *       classWordfru:某类下文档中单词频数
     *       classAllwordnum:某类中总的单词数
     * @param fileDirPath 训练集文件夹目录
     */

 

package com.naivebayes.bnc;



import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import jeasy.analysis.MMAnalyzer;

/**
 * @公式 P( Category | Document) = (P ( Document | Category ) * P( Category))/ P(Document)
 * @朴素贝叶斯分类器: P(c|d)~=P(c)*P(d|c)
 * @算法思想:
 *        训练阶段:对每一个W_k,C_i估计先验条件概率P(w_k|c_i)和概率P(C_i)
 *        分类阶段:计算后验概率,返回使后验概率最大的类
 *        C(d)=argmax {P(C_i)*P(d|c_i)}
 * @条件:给定目标值时属性之间相互条件独立。换言之。该假定说明给定实例的目标值情况下。观察到联合的a1,a2...an的概率正好是对每个单独属性的概率乘积: P(a1,a2...an | Vj ) =Πi P( ai| Vj ).
 * @缺点: 在属性个数比较多或者属性之间相关性较大时,NBC模型的分类效率比不上决策树模型。
 * @优点:决策树模型也有一些缺点,比如处理缺失数据时的困难,过度拟合问题的出现,以及忽略数据集中属性之间的相关性等,适用NBC(朴素贝叶斯分类)
 * @比较:在属性相关性较小时,NBC模型的性能稍微良好。属性相关性较小的时候,其他的算法性能也很好,这是由于信息熵理论决定的。
 * @author 白宁超
 *
 */
 public class NaiveBayesToClass {
    //统计某类文档的数目
    public static Map<String,Integer> classDocnum=new HashMap<String, Integer>();     
    //属于类别的单词 总数
    public static int classAlldocnum=0; 
    //统计某类中某个单词出现的次数
    public static Map<String,Integer> classWordfru=new HashMap<String, Integer>(); 
    //统计某类中的单词总数
    public static Map<String,Integer> classAllwordnum=new HashMap<String, Integer>(); 
    /**
     * 朴素贝叶斯文本分类器
     * 训练阶段
     * 算法思想:文档d属于某类c的概率=文档空间随机抽取一个文档d属于某类c的概率*文档中的单词与总单词的比例
     *        P(c|d)~=P(c)*P(d|c)
     *        P(c)=classDocnum/classAlldocnum
     * 计算参数:
     *       classDocnum:某类中的文档数目
     *       classAlldocnum:数据集中总的文档数目
     *       classWordfru:某类下文档中单词频数
     *       classAllwordnum:某类中总的单词数
     * @param fileDirPath 训练集文件夹目录
     */
    public static void  BayesModel(String fileDirPath){
        try{
            File dir=new File(fileDirPath);
            if(dir.exists()&&dir.isDirectory()){
                File[] files=dir.listFiles();  //获取所有训练集文件
                for(File file:files){
                    String classNo=file.getName().split("\\_")[0];//获取文件类标
                    FileInputStream   stream=new FileInputStream(file);     //获取文件流
                    InputStreamReader strRead=new InputStreamReader(stream,"UTF-8"); //对文件进行读取,且指定编码格式
                    BufferedReader bufReader = new BufferedReader(strRead);
                    String line=null;
                    //读取文件内容
                    while((line=bufReader.readLine())!=null){
                        //统计某类文档的数目
                        if(classDocnum.containsKey(classNo)){
                            classDocnum.put(classNo, classDocnum.get(classNo)+1);
                        }
                        else{
                            classDocnum.put(classNo, 1);//第一次存数据,没有类标,但是已经读取一行,故设置1
                        }
                        String lineText = line.trim(); //除去字符串开头和末尾的空格或其他字符
                        String[] words = lineText.split(" "); 
                        //遍历所有单词
                        for(String word:words){
                            //统计某类中的单词总数
                            if(classAllwordnum.containsKey(classNo)){
                                classAllwordnum.put(classNo, classAllwordnum.get(classNo)+1);
                            }
                            else{
                                classAllwordnum.put(classNo, 1);
                            }
                            //统计某类中某个单词出现的次数
                            String wordNo=classNo+"_"+word;
                            if(classWordfru.containsKey(wordNo)){
                                classWordfru.put(wordNo, classWordfru.get(wordNo)+1);
                            }
                            else{
                                classWordfru.put(wordNo, 1);
                            }
                        }
                        classAlldocnum++;
                    }
                    strRead.close();
                }
            }
            else{
                System.out.println("找不到目录文件"+fileDirPath);
            }    
        }
        catch (Exception e) {
            System.out.println("出错信息描述如下:"+e.getMessage());
        }
    }
    /**
     * 对测试文本进行分类预测
     * 预测阶段:
     * @param testText  测试数据集
     * @return 返回分类结果
     */
    public static String PredictReslut(String testText){
        //预测结果
        String PredictResult="";
        testText=SplitWords(testText, " ");// 对测试文档进行中文分词处理
        String[] words=testText.split(" ");  //对字符串进行分割
        double argmax = Double.NEGATIVE_INFINITY;//最大类概率(默认值为负无穷小),是否可以写成0?(无穷小本身就是接近0)
        Iterator iterator=classDocnum.keySet().iterator();//遍历
        while(iterator.hasNext()){
            String classNo = (String) iterator.next();
            double prior = classDocnum.get(classNo)/(double)classAlldocnum;//先验概率
            double classcount=(double)(classAllwordnum.get(classNo)+1);//某一类的最大值
            double likelihoodProbability=0;                           //初始化似然概率
            //根据公式求解最大似然概率,其中words相当于属性即多维的
            for (int i = 0; i < words.length; i++){
                String word_classNo = words[i]+"_"+classNo;              //获取测试数据的单词类别
                //与训练数据词库进行对比,求得相似的概率
                if(classWordfru.containsKey(word_classNo)){
                    //将连乘装换成对数相加【ln(a*b)=lna+lnb】,提高效率
                    likelihoodProbability += Math.log(classWordfru.get(word_classNo)/classcount);
                }
                else{
                    likelihoodProbability += Math.log(1/classcount);
                }
            }
            //利用自然对数e^loga = a,取得原始值 
            likelihoodProbability = Math.exp(likelihoodProbability)*prior;
             System.out.println("classNo:"+classNo);
             System.out.println("最大似然概率:"+argmax);
             System.out.println("似然概率:"+likelihoodProbability);
             if(likelihoodProbability>argmax){
                 argmax = likelihoodProbability;  //最大似然概率一直保持最大的似然概率
                 PredictResult = classNo;  //返回分类的结果
             }
        }
        System.out.println("***************************************************");
        System.out.println("【朴素贝叶斯最终分类结果:】"+PredictResult);
        return PredictResult;
    }
    
    /**
     * 对字符串进行中文分词处理
     * @param text   给定预处理的字符串
     * @param splitToken  用于分割的标记。如","
     * @return  处理后的字符串
     */
    public static String SplitWords(String text,String splitToken){
        String result = null;
        MMAnalyzer analyzer = new MMAnalyzer();      //极易中文分词
        try      {
            result = analyzer.segment(text, splitToken);    
        }      
        catch (IOException e){     
            e.printStackTrace();     
        }     
        return result;
    }
}
View Code

相关文章:

猜你喜欢
  • 2022-12-23
  • 2021-05-27
  • 2022-12-23
  • 2021-10-17
  • 2022-12-23
  • 2021-08-01
  • 2021-07-08
相关资源
相似解决方案