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

<meta content="text/html; charset=utf-8" http-equiv="CONTENT-TYPE"> <meta content="OpenOffice.org 2.3 (Linux)" name="GENERATOR"> <style type="text/css"> <!-- @page { size: 8.5in 11in; margin: 0.79in } P { margin-bottom: 0.08in } H2 { margin-bottom: 0.08in } H2.cjk { font-family: "AR PL ShanHeiSun Uni" } H3 { margin-bottom: 0.08in } H3.western { font-family: "Helvetica" } H3.cjk { font-family: "AR PL ZenKai Uni" } H4 { margin-bottom: 0.08in } H4.western { font-family: "Helvetica"; font-size: 11pt; font-style: italic } H4.cjk { font-family: "AR PL ZenKai Uni"; font-size: 11pt; font-style: italic } H4.ctl { font-size: 11pt; font-style: italic } H5 { margin-bottom: 0.08in } H5.western { font-family: "Helvetica"; font-size: 11pt } H5.cjk { font-family: "AR PL ZenKai Uni"; font-size: 11pt } H5.ctl { font-size: 11pt } TD P { margin-bottom: 0in } TH P { margin-bottom: 0in } PRE.cjk { font-family: "AR PL ShanHeiSun Uni", monospace } H1 { margin-bottom: 0.08in } H1.western { font-family: "Helvetica"; font-size: 16pt } H1.cjk { font-family: "AR PL ZenKai Uni"; font-size: 16pt } H1.ctl { font-family: "Tahoma"; font-size: 16pt } CODE.cjk { font-family: "AR PL ShanHeiSun Uni", monospace } TT.cjk { font-family: "AR PL ShanHeiSun Uni", monospace } --> </style>

<meta content="text/html; charset=utf-8" http-equiv="CONTENT-TYPE">

<meta content="OpenOffice.org 2.3 (Linux)" name="GENERATOR"> <style type="text/css"> <!-- @page { size: 8.5in 11in; margin: 0.79in } P { margin-bottom: 0.08in } --> </style>




转载请保留作者信息:

作者:88250

Blog:http:/blog.csdn.net/DL88250

MSN & Gmail & QQ:DL88250@gmail.com

引言

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

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

目前,文本自动分类算法基本都是基于概率统计模型的,例如贝叶斯分类算法(Naive Bayes,Bayes 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, …Bn为E的一组事件,若

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

B1∪B2∪…∪Bn=S

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

定理 设试验E的样本空间为,A为E的事件,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的样本空间为S,A为E的事件,B1, B2, …,Bn为的一个划分,则

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

称为贝叶斯公式。

说明:i,j均为下标,求和均是1到n



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

Lucene:lucene-core-2.3.0.jar

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

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

工程分为了两个包:bayes和util

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

Class Summary

BayesClassifier

朴素贝叶斯分类器

ClassifyResult

分类结果实体



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

 

 

朴素贝叶斯分类器

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


<!-- ======== CONSTRUCTOR SUMMARY ======== --><!-- -->

Constructor Summary

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

<!-- ========== METHOD SUMMARY =========== --><!-- -->

Method Summary

java.lang.String

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

<!-- -->

Methods inherited from class java.lang.Object

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

<!-- ========= CONSTRUCTOR DETAIL ======== --><!-- -->

Constructor Detail

<!-- -->BayesClassifier

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

<!-- ============ METHOD DETAIL ========== --><!-- -->

Method Detail

<!-- -->classify

 
对给定的文本进行分类
Parameters:
text - 给定的文本
Returns:
分类结果



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

 

 

分类结果实体


<!-- =========== FIELD SUMMARY =========== --><!-- -->

Field Summary

java.lang.String

classification
类别

float

p
概率

<!-- ======== CONSTRUCTOR SUMMARY ======== --><!-- -->

Constructor Summary

ClassifyResult()

<!-- ========== METHOD SUMMARY =========== --><!-- -->

Method Summary

<!-- -->

Methods inherited from class java.lang.Object

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

<!-- ============ FIELD DETAIL =========== --><!-- -->

Field Detail

<!-- -->classification

 
类别

<!-- -->p

 
概率

<!-- ========= CONSTRUCTOR DETAIL ======== --><!-- -->

Constructor Detail

<!-- -->ClassifyResult

 

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

Class Summary

ChineseSpliter

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

ClassConditionalProbability

条件概率计算

KeySearcher

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

PriorProbability

先验概率计算

TrainingDataManager

训练语料库搜索器

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

 

 

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


<!-- ======== CONSTRUCTOR SUMMARY ======== --><!-- -->

Constructor Summary

ChineseSpliter()

<!-- ========== METHOD SUMMARY =========== --><!-- -->

Method Summary

staticjava.lang.String

split(java.lang.Stringtext, java.lang.StringsplitToken)
中文分词

<!-- -->

Methods inherited from class java.lang.Object

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

<!-- ========= CONSTRUCTOR DETAIL ======== --><!-- -->

Constructor Detail

<!-- -->ChineseSpliter

 

<!-- ============ METHOD DETAIL ========== --><!-- -->

Method Detail

<!-- -->split

 
中文分词
Parameters:
text - 给定的文本
splitToken - 用于分割的标记
Returns:
分词完毕的文本

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

 

 

条件概率计算

类条件概率

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 ======== --><!-- -->

Constructor Summary

ClassConditionalProbability()

<!-- ========== METHOD SUMMARY =========== --><!-- -->

Method Summary

staticfloat

calculatePxc(java.lang.Stringx, java.lang.Stringc)
计算类条件概率

<!-- -->

Methods inherited from class java.lang.Object

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

<!-- ========= CONSTRUCTOR DETAIL ======== --><!-- -->

Constructor Detail

<!-- -->ClassConditionalProbability

 

<!-- ============ METHOD DETAIL ========== --><!-- -->

Method Detail

<!-- -->calculatePxc

 
计算类条件概率
Parameters:
x - 给定的文本属性
c - 给定的分类
Returns:
给定条件下的类条件概率

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

 

 

先验概率计算

先验概率计算

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


<!-- ======== CONSTRUCTOR SUMMARY ======== --><!-- -->

Constructor Summary

PriorProbability()

<!-- ========== METHOD SUMMARY =========== --><!-- -->

Method Summary

staticfloat

calculatePc(java.lang.Stringc)
先验概率

<!-- -->

Methods inherited from class java.lang.Object

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

<!-- ========= CONSTRUCTOR DETAIL ======== --><!-- -->

Constructor Detail

<!-- -->PriorProbability

 

<!-- ============ METHOD DETAIL ========== --><!-- -->

Method Detail

<!-- -->calculatePc

 
先验概率
Parameters:
c - 给定的分类
Returns:
给定条件下的先验概率

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

 

 

训练语料库搜索器


<!-- ======== CONSTRUCTOR SUMMARY ======== --><!-- -->

Constructor Summary

TrainingDataManager()
默认的构造器

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

<!-- ========== METHOD SUMMARY =========== --><!-- -->

Method Summary

int

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

java.lang.String[]

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

staticjava.lang.String

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

int

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

int

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

java.lang.String[]

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

<!-- -->

Methods inherited from class java.lang.Object

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

<!-- ========= CONSTRUCTOR DETAIL ======== --><!-- -->

Constructor Detail

<!-- -->TrainingDataManager

 
带参数的构造器
Parameters:
traningDataDirPath - 训练语料库根目录路径

<!-- -->TrainingDataManager

 
默认的构造器

<!-- ============ METHOD DETAIL ========== --><!-- -->

Method Detail

<!-- -->getTraningClassifications

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

<!-- -->getFilesPath

 
根据训练文本类别返回这个类别下的所有训练文本路径(full path)
Parameters:
classification - 给定的分类
Returns:
给定分类下所有文件的路径(full path )

<!-- -->getText

 
返回给定路径的文本文件内容
Parameters:
filePath - 给定的文本文件路径
Returns:
文本内容
Throws:
java.io.FileNotFoundException
java.io.IOException

<!-- -->getTrainingFileCount

 
返回训练文本集中所有的文本数目
Returns:
训练文本集中所有的文本数目

<!-- -->getTrainingFileCountOfClassification

 
返回训练文本集中在给定分类下的训练文本数目
Parameters:
classification - 给定的分类
Returns:
训练文本集中在给定分类下的训练文本数目

<!-- -->getCountContainKeyOfClassification

 
返回给定分类中包含关键字/词的训练文本的数目
Parameters:
classification - 给定的分类
key - 给定的关键字/词
Returns:
给定分类中包含关键字/词的训练文本的数目



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



3. 关键源代码清单
/*

*@(#)TrainingDataManager.java

*

*Thisprogramisfreesoftware;youcanredistributeitand/ormodify

*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby

*theFreeSoftwareFoundation;eitherversion3oftheLicense,or

*(atyouroption)anylaterversion.

*

*Thisprogramisdistributedinthehopethatitwillbeuseful,

*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof

*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe

*GNULibraryGeneralPublicLicenseformoredetails.

*

*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense

*alongwiththisprogram;ifnot,writetotheFreeSoftware

*Foundation,Inc.,59TemplePlace-Suite330,Boston,MA02111-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,Feb18,2008

*/

public class TrainingDataManager{



private String[]traningFileClassifications;



private FiletraningTextDir;



/**

*带参数的构造器

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

*/

public TrainingDataManager(StringtraningDataDirPath){

traningTextDir
= new File(traningDataDirPath);



if ( ! traningTextDir.isDirectory()){

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

traningDataDirPath
+ " ] " );

}



this .traningFileClassifications = traningTextDir.list();

}



/**

*默认的构造器

*/

public TrainingDataManager(){

try {

Propertiesproperties
= new Properties();

FileInputStreaminputFile;

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

properties.load(inputFile);



StringtraningDataDirPath
= properties.getProperty( " path " );

traningTextDir
= new File(traningDataDirPath);



if ( ! traningTextDir.isDirectory()){

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

traningDataDirPath
+ " ] " );

}



this .traningFileClassifications = traningTextDir.list();

}
catch (IOExceptionex){

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

log(Level.SEVERE,
null ,ex);

}

}



/**

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

*
@return 训练文本类别

*/

public String[]getTraningClassifications(){

return this .traningFileClassifications;

}



/**

*根据训练文本类别返回这个类别下的所有训练文本路径(fullpath)

*
@param classification给定的分类

*
@return 给定分类下所有文件的路径(fullpath)

*/

public String[]getFilesPath(Stringclassification){

FileclassDir
= 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 StringgetText(StringfilePath) throws FileNotFoundException,

IOException{

InputStreamReaderisReader
=

new InputStreamReader( new FileInputStream(filePath),

" GBK " );

BufferedReaderreader
= new BufferedReader(isReader);



Stringaline;

StringBuildersb
= 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(Stringclassification){

FileclassDir
= new File(traningTextDir.getPath() +

File.separator
+

classification);

return classDir.list().length;

}



/**

*返回给定分类中包含关键字/词的训练文本的数目

*
@param classification给定的分类

*
@param key给定的关键字/词

*
@return 给定分类中包含关键字/词的训练文本的数目

*/

public int getCountContainKeyOfClassification(Stringclassification,

Stringkey){

int ret = 0 ;



try {

String[]filePath
= getFilesPath(classification);

for ( int j = 0 ;j < filePath.length;j ++ ){

Stringtext
= getText(filePath[j]);

if (text.contains(key)){

ret
++ ;

}

}

}
catch (FileNotFoundExceptionex){

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

log(Level.SEVERE,
null ,

ex);

}
catch (IOExceptionex){

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

log(Level.SEVERE,
null ,

ex);

}

return ret;



}

}



/*

*@(#)PriorProbability.java

*

*Thisprogramisfreesoftware;youcanredistributeitand/ormodify

*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby

*theFreeSoftwareFoundation;eitherversion3oftheLicense,or

*(atyouroption)anylaterversion.

*

*Thisprogramisdistributedinthehopethatitwillbeuseful,

*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof

*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe

*GNULibraryGeneralPublicLicenseformoredetails.

*

*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense

*alongwiththisprogram;ifnot,writetotheFreeSoftware

*Foundation,Inc.,59TemplePlace-Suite330,Boston,MA02111-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,Feb19,2008

*/

public class PriorProbability{



private static TrainingDataManagertdm =

new TrainingDataManager();



/**

*先验概率

*
@param c给定的分类

*
@return 给定条件下的先验概率

*/

public static float calculatePc(Stringc){

float ret = 0F;



float Nc = tdm.getTrainingFileCountOfClassification(c);



float N = tdm.getTrainingFileCount();

ret
= Nc / N;



return ret;

}

}



/*

*@(#)ClassConditionalProbability.java

*

*Thisprogramisfreesoftware;youcanredistributeitand/ormodify

*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby

*theFreeSoftwareFoundation;eitherversion3oftheLicense,or

*(atyouroption)anylaterversion.

*

*Thisprogramisdistributedinthehopethatitwillbeuseful,

*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof

*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe

*GNULibraryGeneralPublicLicenseformoredetails.

*

*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense

*alongwiththisprogram;ifnot,writetotheFreeSoftware

*Foundation,Inc.,59TemplePlace-Suite330,Boston,MA02111-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,Feb19,2008

*/

public class ClassConditionalProbability{



private static TrainingDataManagertdm =

new TrainingDataManager();



private static final float M = 0F;



/**

*计算类条件概率

*
@param x给定的文本属性

*
@param c给定的分类

*
@return 给定条件下的类条件概率

*/

public static float calculatePxc(Stringx,Stringc){

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

*

*Thisprogramisfreesoftware;youcanredistributeitand/ormodify

*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby

*theFreeSoftwareFoundation;eitherversion3oftheLicense,or

*(atyouroption)anylaterversion.

*

*Thisprogramisdistributedinthehopethatitwillbeuseful,

*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof

*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe

*GNULibraryGeneralPublicLicenseformoredetails.

*

*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense

*alongwiththisprogram;ifnot,writetotheFreeSoftware

*Foundation,Inc.,59TemplePlace-Suite330,Boston,MA02111-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>=argMaxP(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,Feb19,2008

*/

public class BayesClassifier{



private TrainingDataManagertdm;



/**

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

*/

public BayesClassifier(){

try {

Propertiesproperties
= new Properties();



FileInputStreaminputFile;

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



properties.load(inputFile);



tdm
=

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

}
catch (IOExceptionex){

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,StringCj){

float ret = 0F;



// 类条件概率连乘

for ( int i = 0 ;i <

X.length;i
++ ){

StringXi
= X[i];

ret
+=

ClassConditionalProbability.calculatePxc(Xi,Cj);

}

// 再乘以先验概率

ret
*= PriorProbability.calculatePc(Cj);



return ret;

}



/**

*对给定的文本进行分类

*
@param text给定的文本

*
@return 分类结果

*/

@SuppressWarnings(
" unchecked " )

public Stringclassify(

Stringtext){

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
++ ){

StringCi
= C[i];

p
=

calcProd(X,Ci);

ClassifyResultcr
= new ClassifyResult();

cr.classification
= Ci;

cr.p
= p;

System.out.println(
" Inprocess.... " );

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

crs.add(cr);

}



java.util.Collections.sort(crs,

new Comparator(){



public int compare(Objecto1,

Objecto2){

ClassifyResultm1
=

(ClassifyResult)o1;

ClassifyResultm2
=

(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个字,在没有经过任何降维处理的情况下,使用稍大一点的词库后,性能问题出来了。

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



后话

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

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

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

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

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值