D 的个人博客

但行好事莫问前程

  menu
417 文章
3446695 浏览
5 当前访客
ღゝ◡╹)ノ❤️

朴素贝叶斯中文文本分类器的研究与实现(1)[88250原创]




转载请保留作者信息:

作者:88250

Bloghttp:/blog.csdn.net/DL88250

MSN & Gmail & QQ[email protected]

 

引言

将文本信息按预先指定的类别归类的技术可以追溯到上世纪60年代。不过,在最近的10年里,由于文本信息数字化而带来的海量数据,导致我们不得不将这些信息进行分类。由此,文本信息的自动分类得到了广泛的关注和快速的发展。

一 些研究表明,机器学习技术解决这个问题是较为有效的方法:通过一种广义的诱导学习建立相应的自动分类器,形成预先文档信息的一个或多个特征的分类集合。基 于机器学习的分类方式在分类效果和灵活性上都比之前基于知识工程和专家系统(通过某个领域里的专家人为地定义分类器)的文本分类模式有所突破,大量节省了 专家人力的投入,可以很方便地用于各种不同的领域。

目前,文本自动分类算法基本都是基于概率统计模型的,例如贝叶斯分类算法(Naive BayesBayes Network),支持向量机(SVM),最大熵模型(Maximum Entropy Model),K近邻算法(KMM)等等。本文就基于概率模型的朴素贝叶斯分类算法作了一些讨论,并根据理论描述使用Java语言构建了一个素朴贝叶斯分类器。实验表明,贝叶斯分类算法简单,可以取得了优良的分类效果。


正文

一 贝叶斯理论与中文文本分类概述

1. 基本概念

条件概率

定义 设A, B是两个事件,且P(A)>0

P(B∣A)=P(AB)/P(A)

为在条件A下发生的条件事件B发生的条件概率。

乘法公式

P(A)>0 则有

P(AB)=P(B∣A)P(A)

全概率公式和贝叶斯公式

定义S为试验E的样本空间,B1, B2, …BnE的一组事件,若

  1. BiBj≠Ф, i≠j, i, j=1, 2, …,n;

     

B1∪B2∪…∪Bn=S

则称B1, B2, …, Bn为样本空间的一个划分。

定理 设试验E的样本空间为,AE的事件,B1, B2, …,Bn为的一个划分,且P(Bi)>0 (i=1, 2, …n),则

P(A)=P(A∣B1)P(B1)+P(A∣B2)+ …+P(A∣Bn)P(Bn)

称为全概率公式。

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

P(Bi∣A)=P(A∣Bi)P(Bi)/∑P(BAj)P(Aj)=P(BAi)P(Ai)/P(B)

称为贝叶斯公式。

说明:ij均为下标,求和均是1n  



2. 朴素贝叶斯模型的假设与文本特征变量

文本特征变量

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

Ding Liang is a programmer.

可以获得该文本的特征变量集:{Ding, Liang, is, a, programmer.}

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

虽然这种条件独立的假设在许多应用领域未必能很好满足,甚至是不成立的。但这种简化的贝叶斯分类器在许多实际应用中还是得到了较好的分类精度。


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

3. 中文分词

中文分词的概念、意义以及算法简介可以查看 这篇文章 :-)

关于中文分词的实际可用工具,前人已经做了很多成功的实践:

ICTCLAS

中科院的ICTCLAS(Institute of Computing Technology, Chinese Lexical Analysis System)应该是目前最好的中文分词系统了。不过1.0版本后收费了,而且是在Windows下封装的DLL库,要作移植比较困难。

ICTCLAS4J

Java版本的开源LCTCLAS,由于代码的开发人员没有太多考虑到跨平台,导致了在非Windows平台上的配置比较繁琐。并且,其提供的接口不是很友好,其词库的依赖关系颇为复杂。

海量分词组件

海量信息的中文智能分词组件虽然可以免费使用,但是也是提供的DLL,没有平台移植性。

极易中文分词组件

由极易软件提供的极易中文分词组件可以免费使用,提供Lucene接口,跨平台,性能可靠。



本次分类器是使用Java语言编写的,所以选择了极易中文分词组件作为基本的分词工具。



4. 朴素贝叶斯分类推导

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



 


 


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

二  用Java构造朴素贝叶斯中文文本分类器

在前面,我们介绍了贝叶斯理论与中文分词技术。现在,让我们实践吧!

1. 开发环境与工具配置

OS: Ubuntu 7.10 GNU/Linux

IDE:NetBeans 6.0.1

JDK: 1.6.0_03-b05

Lucenelucene-core-2.3.0.jar

分词工具:je-analysis-1.5.3.jar (极易分词组件1.5.3

2. 朴素贝叶斯分类器设计

工程分为了两个包:bayesutil

Package cn.edu.ynu.sei.classifier.bayes

Class Summary

BayesClassifier

朴素贝叶斯分类器

ClassifyResult

分类结果实体



n.edu.ynu.sei.classifier.bayes
Class BayesClassifier

java.lang.Object   extended by cn.edu.ynu.sei.classifier.bayes.BayesClassifier

public class BayesClassifierextends java.lang.Object

朴素贝叶斯分类器

cNB=arg Max P(cj)∏1C P(xi|cj)



Constructor Summary

BayesClassifier()
          默认的构造器,初始化训练库路径

 

 

Method Summary

 java.lang.String

classify(java.lang.String text)
          对给定的文本进行分类

 

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

 


Constructor Detail

BayesClassifier

public BayesClassifier()
默认的构造器,初始化训练库路径


Method Detail

classify

public java.lang.String classify(java.lang.String text)
对给定的文本进行分类
Parameters:
text - 给定的文本
Returns:
分类结果



cn.edu.ynu.sei.classifier.bayes
Class ClassifyResult

java.lang.Object   extended by cn.edu.ynu.sei.classifier.bayes.ClassifyResult

public class ClassifyResultextends java.lang.Object

分类结果实体



Field Summary

 java.lang.String

classification
          类别

 float

p
          概率

 

Constructor Summary

ClassifyResult()
           

 

 

Method Summary

 

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

 


Field Detail

classification

public java.lang.String classification
类别

p

public float p
概率


Constructor Detail

ClassifyResult

public ClassifyResult()




Package cn.edu.ynu.sei.classifier.util

Class Summary

ChineseSpliter

中文分词器 简单地封装了一下极易中文分词组件

ClassConditionalProbability

条件概率计算

KeySearcher

关键字/词搜索器 简单地封装了一下极易中文分词组件

PriorProbability

先验概率计算

TrainingDataManager

训练语料库搜索器

 

cn.edu.ynu.sei.classifier.util
Class ChineseSpliter

java.lang.Object   extended by cn.edu.ynu.sei.classifier.util.ChineseSpliter

public class ChineseSpliterextends java.lang.Object

中文分词器 简单地封装了一下极易中文分词组件



Constructor Summary

ChineseSpliter()
           

 

 

Method Summary

static java.lang.String

split(java.lang.String text, java.lang.String splitToken)
          中文分词

 

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

 


Constructor Detail

ChineseSpliter

public ChineseSpliter()


Method Detail

split

public static java.lang.String split(java.lang.String text,                                      java.lang.String splitToken)
中文分词
Parameters:
text - 给定的文本
splitToken - 用于分割的标记
Returns:
分词完毕的文本

cn.edu.ynu.sei.classifier.util
Class ClassConditionalProbability

java.lang.Object   extended by cn.edu.ynu.sei.classifier.util.ClassConditionalProbability

public class ClassConditionalProbabilityextends java.lang.Object

条件概率计算

类条件概率

P(xj|cj)=( N(X=xi, C=cj )+1 ) / ( N(C=cj)+M+V )
其中,N(X=xi, C=cj)表示类别cj中包含属性x i的训练文本数量;N(C=cj)表示类别cj中的训练文本数量;M值用于避免 N(X=xi, C=cj)过小所引发的问题;V表示类别的总数。

条件概率

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



Constructor Summary

ClassConditionalProbability()
           

 

 

Method Summary

static float

calculatePxc(java.lang.String x, java.lang.String c)
          计算类条件概率

 

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

 


Constructor Detail

ClassConditionalProbability

public ClassConditionalProbability()


Method Detail

calculatePxc

public static float calculatePxc(java.lang.String x,                                  java.lang.String c)
计算类条件概率
Parameters:
x - 给定的文本属性
c - 给定的分类
Returns:
给定条件下的类条件概率

cn.edu.ynu.sei.classifier.util
Class PriorProbability

java.lang.Object   extended by cn.edu.ynu.sei.classifier.util.PriorProbability

public class PriorProbabilityextends java.lang.Object

先验概率计算

先验概率计算

P(cj)=N(C=cj)/N
其中,N(C=cj)表示类别cj中的训练文本数量; N表示训练文本集总数量。



Constructor Summary

PriorProbability()
           

 

 

Method Summary

static float

calculatePc(java.lang.String c)
          先验概率

 

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

 


Constructor Detail

PriorProbability

public PriorProbability()


Method Detail

calculatePc

public static float calculatePc(java.lang.String c)
先验概率
Parameters:
c - 给定的分类
Returns:
给定条件下的先验概率

cn.edu.ynu.sei.classifier.util
Class TrainingDataManager

java.lang.Object   extended by cn.edu.ynu.sei.classifier.util.TrainingDataManager

public class TrainingDataManagerextends java.lang.Object

训练语料库搜索器



Constructor Summary

TrainingDataManager()
          默认的构造器

 

TrainingDataManager(java.lang.String traningDataDirPath)
          带参数的构造器

 

 

Method Summary

 int

getCountContainKeyOfClassification(java.lang.String classification, java.lang.String key)
          返回给定分类中包含关键字/词的训练文本的数目

 java.lang.String[]

getFilesPath(java.lang.String classification)
          根据训练文本类别返回这个类别下的所有训练文本路径(full path

static java.lang.String

getText(java.lang.String filePath)
          返回给定路径的文本文件内容

 int

getTrainingFileCount()
          返回训练文本集中所有的文本数目

 int

getTrainingFileCountOfClassification(java.lang.String classification)
          返回训练文本集中在给定分类下的训练文本数目

 java.lang.String[]

getTraningClassifications()
          返回训练文本类别,这个类别就是目录名

 

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

 


Constructor Detail

TrainingDataManager

public TrainingDataManager(java.lang.String traningDataDirPath)
带参数的构造器
Parameters:
traningDataDirPath - 训练语料库根目录路径

TrainingDataManager

public TrainingDataManager()
默认的构造器


Method Detail

getTraningClassifications

public java.lang.String[] getTraningClassifications()
返回训练文本类别,这个类别就是目录名
Returns:
训练文本类别

getFilesPath

public java.lang.String[] getFilesPath(java.lang.String classification)
根据训练文本类别返回这个类别下的所有训练文本路径(full path
Parameters:
classification - 给定的分类
Returns:
给定分类下所有文件的路径(full path

getText

public static java.lang.String getText(java.lang.String filePath)                                 throws java.io.FileNotFoundException,                                        java.io.IOException
返回给定路径的文本文件内容
Parameters:
filePath - 给定的文本文件路径
Returns:
文本内容
Throws:
java.io.FileNotFoundException
java.io.IOException

getTrainingFileCount

public int getTrainingFileCount()
返回训练文本集中所有的文本数目
Returns:
训练文本集中所有的文本数目

getTrainingFileCountOfClassification

public int getTrainingFileCountOfClassification(java.lang.String classification)
返回训练文本集中在给定分类下的训练文本数目
Parameters:
classification - 给定的分类
Returns:
训练文本集中在给定分类下的训练文本数目

getCountContainKeyOfClassification

public int getCountContainKeyOfClassification(java.lang.String classification,                                               java.lang.String key)
返回给定分类中包含关键字/词的训练文本的数目
Parameters:
classification - 给定的分类
key - 给定的关键字/词
Returns:
给定分类中包含关键字/词的训练文本的数目



以上便是当前阶段下的分类器设计,为了更进一步说明,下面列出关键的源代码:-)



3. 关键源代码清单

/*

* @(#)TrainingDataManager.java

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU Library General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

package cn.edu.ynu.sei.classifier.util;



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;



/**

* 训练语料库搜索器

@author 88250

@version 1.0.0.0, Feb 18, 2008

*/

public class TrainingDataManager {



private String[] traningFileClassifications;



private File traningTextDir;



/**

* 带参数的构造器

@param traningDataDirPath 训练语料库根目录路径

*/

public TrainingDataManager(String traningDataDirPath) {

traningTextDir 
= new File(traningDataDirPath);



if (!traningTextDir.isDirectory()) {

throw new IllegalArgumentException("训练语料库搜索失败! [" +

traningDataDirPath 
+ "]");

}



this.traningFileClassifications = traningTextDir.list();

}



/**

* 默认的构造器

*/

public TrainingDataManager() {

try {

Properties properties 
= new Properties();

FileInputStream inputFile;

inputFile 
= new FileInputStream("/home/daniel/TempData/BayesTextClassifySystem/Training.properties");

properties.load(inputFile);



String traningDataDirPath 
= properties.getProperty("path");

traningTextDir 
= new File(traningDataDirPath);



if (!traningTextDir.isDirectory()) {

throw new IllegalArgumentException("训练语料库搜索失败! [" +

traningDataDirPath 
+ "]");

}



this.traningFileClassifications = traningTextDir.list();

catch (IOException ex) {

Logger.getLogger(TrainingDataManager.
class.getName()).

log(Level.SEVERE, 
null, ex);

}

}



/**

* 返回训练文本类别,这个类别就是目录名

@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;



}

}



/*

* @(#)PriorProbability.java

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU Library General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

package cn.edu.ynu.sei.classifier.util;



/**

* 先验概率计算

* <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表示训练文本集总数量。

@author 88250

@version 1.0.0.0, Feb 19, 2008

*/

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;

}

}



/*

* @(#)ClassConditionalProbability.java

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU Library General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

package cn.edu.ynu.sei.classifier.util;



/**

* <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发生的条件概率。

@author 88250

@version 1.0.0.0, Feb 19, 2008

*/

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);



return ret;

}

}



/*

* @(#)BayesClassifier.java

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU Library General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

package cn.edu.ynu.sei.classifier.bayes;



import cn.edu.ynu.sei.classifier.util.ChineseSpliter;

import cn.edu.ynu.sei.classifier.util.ClassConditionalProbability;

import cn.edu.ynu.sei.classifier.util.PriorProbability;

import cn.edu.ynu.sei.classifier.util.TrainingDataManager;

import java.io.FileInputStream;

import java.io.IOException;

import java.util.ArrayList;

import java.util.Comparator;

import java.util.List;

import java.util.Properties;

import java.util.Properties;

import java.util.logging.Level;

import java.util.logging.Logger;



/**

* 朴素贝叶斯分类器

* <p>

* c<sub>NB</sub>=arg Max P(c<sub>j</sub>)&prod;<sub>1</sub><sup>C</sup>

* P(x<sub>i</sub>|c<sub>j</sub>)

* </p>

@author 88250

@version 1.0.0.0, Feb 19, 2008

*/

public class BayesClassifier {



private TrainingDataManager tdm;



/**

* 默认的构造器,初始化训练库路径

*/

public BayesClassifier() {

try {

Properties properties 
= new Properties();



FileInputStream inputFile;

inputFile 
= new FileInputStream("/home/daniel/TempData/BayesTextClassifySystem/Training.properties");



properties.load(inputFile);



tdm 
=

new TrainingDataManager(properties.getProperty("path"));

catch (IOException ex) {

Logger.getLogger(BayesClassifier.
class.getName()).

log(Level.SEVERE, 
null, ex);

}

}



/**

* 计算给定的文本属性向量<code>X</code>在给定的分类<code>Cj</code>中的类条件概率

* <code>ClassConditionalProbability</code>连乘(&prod;)值

@param X 给定的文本属性向量

@param Cj 给定的类别

@return 类条件概率连乘(&prod;)值,即<br>

* P(c<sub>j</sub>)&prod;<sub>1</sub><sup>C</sup> P(x<sub>i</sub>|c<sub>j</sub>)

@see cn.edu.ynu.sei.classifier.util.ClassConditionalProbability

*/

float calcProd(String[] X, String Cj) {

float ret = 0F;



// 类条件概率连乘

for (int i = 0; i <

X.length; i
++) {

String Xi 
= X[i];

ret 
+=

ClassConditionalProbability.calculatePxc(Xi, Cj);

}

// 再乘以先验概率

ret 
*= PriorProbability.calculatePc(Cj);



return ret;

}



/**

* 对给定的文本进行分类

@param text 给定的文本

@return 分类结果

*/

@SuppressWarnings(
"unchecked")

public String classify(

String text) {

String[] X 
= ChineseSpliter.split(text, " ").split("\s");

String[] C 
= tdm.getTraningClassifications();

float p = 0F;

List
<ClassifyResult> crs = new ArrayList<ClassifyResult>();



for (int i = 0; i <

C.length; i
++) {

String Ci 
= C[i];

=

calcProd(X, Ci);

ClassifyResult cr 
= new ClassifyResult();

cr.classification 
= Ci;

cr.p 
= p;

System.out.println(
"In process....");

System.out.println(Ci 
+ "" + p);

crs.add(cr);

}



java.util.Collections.sort(crs,

new Comparator() {



public int compare(Object o1,

Object o2) {

ClassifyResult m1 
=

(ClassifyResult) o1;

ClassifyResult m2 
=

(ClassifyResult) o2;

float ret = m1.p - m2.p;

if (ret < 0) {

return 1;

else {

return -1;

}

}

});



return crs.get(0).classification;

}

}



三 训练库与分类测试

作为测试,我用的是Sogou实验室的文本分类数据下载了mini版本和精简版本。

迷你版本有10个类别 ,共计100篇文章,总大小284.7KB

精简版本有9个类别,共计17910篇文章,总大小 48.6 MB

测试机器配置:

Pm 750(1.86G), 1.0GB RAM


对于给定的文本:

[ 微软公司提出以446亿美元的价格收购雅虎

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

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

微软和雅虎公司在2006年底和2007年初已在寻求双方合作。而近两年,雅虎一直处于困境:市场份额下滑、

运营业绩不佳、股价大幅下跌。对于力图在互联网市场有所作为的微软来说,收购雅虎无疑是一条捷径,因为双方具有非常强的互补性。(小桥)

]



使用mini版本的测试结果:

init:

deps-jar:

compile:

compile-test-single:

Testsuite: cn.edu.ynu.sei.classifier.bayes.BayesClassifierTest

classify

In process....

文化:0.70500064

In process....

健康:0.9200004

In process....

旅游:0.8250006

In process....

招聘:0.89000064

In process....

汽车:1.1150006

In process....

教育:0.82000035

In process....

体育:0.7400004

In process....

IT1.1150006

In process....

财经:1.0150005

In process....

军事:0.76500034



属于[ IT ]

Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 4.572 sec



可以看出,对于该文本,“汽车”的相似度和“IT”是一样的。



使用精简版本的测试结果:

Compiling 1 source file to /home/daniel/Work/Sources/Java/BayesTextClassifier/build/test/classes

compile-test-single:

Testsuite: cn.edu.ynu.sei.classifier.bayes.BayesClassifierTest

classify

In process....

文化:0.7996222

In process....

健康:0.691568

In process....

旅游:0.6269246

In process....

招聘:0.95492196

In process....

教育:0.64076483

In process....

体育:0.41798678

In process....

IT1.2663554

In process....

财经:1.1997666

In process....

军事:0.9136235

属于[ IT ]

Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 594.815 sec





关于分类器的评估

使用Mini版本训练库时,分类耗时4.572秒;

使用精简版本训练库时,分类耗时594.815秒,也就是9分多钟。

测试用的文章只有261个字,在没有经过任何降维处理的情况下,使用稍大一点的词库后,性能问题出来了。

另外,分类器的评估有专门的评估模型和方法,这里不再赘述。



后话

当前,是实验的第一阶段,注重的是“纯”朴素贝叶斯理论研究和实现,所以,在分类效率上可能较为低下。但是,基于本次构建的朴素贝叶斯分类器,下一阶段将对她作出优化处理。目前想到的优化手段:

  1. 文本先进行降维处理,具体方法就是踢出一些无用的词汇(例如:的,吗,么。。。。等等助词之类的)

  2. 在先验条件的处理上要考虑对训练库进行处理后的先验条件数据保存,下次直接读取就可以用了

  3. 找台多核的机子做多线程处理 :-)

好了,本文到此就结束了。下一次的题目是《朴素贝叶斯中文文本分类器的研究与实现(2[88250原创],期待大家的关注!