<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. 朴素贝叶斯分类推导
根据联合概率公式(全概率公式)
二 用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 | |
---|---|
|
<!-- ========== METHOD SUMMARY =========== --><!-- -->
Method Summary | |
---|---|
|
|
Methods inherited from class java.lang.Object |
---|
|
<!-- ========= 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 | |
---|---|
|
|
|
|
<!-- ======== CONSTRUCTOR SUMMARY ======== --><!-- -->
Constructor Summary | |
---|---|
|
<!-- ========== METHOD SUMMARY =========== --><!-- -->
Method Summary |
---|
Methods inherited from class java.lang.Object |
---|
|
<!-- ============ 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 | |
---|---|
|
<!-- ========== METHOD SUMMARY =========== --><!-- -->
Method Summary | |
---|---|
|
|
Methods inherited from class java.lang.Object |
---|
|
<!-- ========= 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 | |
---|---|
|
<!-- ========== METHOD SUMMARY =========== --><!-- -->
Method Summary | |
---|---|
|
|
Methods inherited from class java.lang.Object |
---|
|
<!-- ========= 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 | |
---|---|
|
<!-- ========== METHOD SUMMARY =========== --><!-- -->
Method Summary | |
---|---|
|
|
Methods inherited from class java.lang.Object |
---|
|
<!-- ========= 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 | |
---|---|
| |
|
<!-- ========== METHOD SUMMARY =========== --><!-- -->
Method Summary | |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Methods inherited from class java.lang.Object |
---|
|
<!-- ========= 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>)∏<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>连乘(∏)值
* @param X给定的文本属性向量
* @param Cj给定的类别
* @return 类条件概率连乘(∏)值,即<br>
*P(c<sub>j</sub>)∏<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亿美元的价格收购雅虎
中国网2月1日报道 美联社消息,微软公司提出以446亿美元现金加股票的价格收购搜索网站雅虎公司。
微软提出以每股31美元的价格收购雅虎。微软的收购报价较雅虎1月31日的收盘价19.18美元溢价62%。微软公司称雅虎公司的股东可以选择以现金或股票进行交易。
微软和雅虎公司在2006年底和2007年初已在寻求双方合作。而近两年,雅虎一直处于困境:市场份额下滑、
运营业绩不佳、股价大幅下跌。对于力图在互联网市场有所作为的微软来说,收购雅虎无疑是一条捷径,因为双方具有非常强的互补性。(小桥)
]
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....
IT:1.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....
IT:1.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原创]》,期待大家的关注!