源代码下载:NaviveBayesClassify.rar
Preface
文本的分类和聚类是一个比较有意思的话题,我以前也写过一篇blog《基于K-Means的文本聚类算法》,加上最近读了几本数据挖掘和机器学习的书籍,因此很想写点东西来记录下学习的所得。
在本文的上半部分《基于朴素贝叶斯分类器的文本分类算法(上)》一文中简单介绍了贝叶斯学习的基本理论,这一篇将展示如何将该理论运用到中文文本分类中来,具体的文本分类原理就不再介绍了,在上半部分有,也可以参见代码的注释。
文本特征向量
文本特征向量可以描述为文本中的字/词构成的属性。例如给出文本:
Good good study,Day day up.
可以获得该文本的特征向量集:{ Good, good, study, Day, day , up.}
朴素贝叶斯模型是文本分类模型中的一种简单但性能优越的的分类模型。为了简化计算过程,假定各待分类文本特征变量是相互独立的,即“朴素贝叶斯模型的假设”。相互独立表明了所有特征变量之间的表述是没有关联的。如上例中,[good]和[study]这两个特征变量就是没有任何关联的。
在上例中,文本是英文,但由于中文本身是没有自然分割符(如空格之类符号),所以要获得中文文本的特征变量向量首先需要对文本进行中文分词
中文分词
这里采用极易中文分词组件,这个中文分词组件可以免费使用,提供Lucene接口,跨平台,性能可靠。
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->packagecom.vista;
importjava.io.IOException;
importjeasy.analysis.MMAnalyzer;
/**
*中文分词器
*/
publicclassChineseSpliter
{
/**
*对给定的文本进行中文分词
*@paramtext给定的文本
*@paramsplitToken用于分割的标记,如"|"
*@return分词完毕的文本
*/
publicstaticStringsplit(Stringtext,StringsplitToken)
{
Stringresult=null;
MMAnalyzeranalyzer=newMMAnalyzer();
try
{
result=analyzer.segment(text,splitToken);
}
catch(IOExceptione)
{
e.printStackTrace();
}
returnresult;
}
}
停用词处理
去掉文档中无意思的词语也是必须的一项工作,这里简单的定义了一些常见的停用词,并根据这些常用停用词在分词时进行判断。
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->packagecom.vista;
/**
*停用词处理器
*@authorphinecos
*
*/
publicclassStopWordsHandler
{
privatestaticStringstopWordsList[]={"的","我们","要","自己","之","将","“","”",",","(",")","后","应","到","某","后","个","是","位","新","一","两","在","中","或","有","更","好",""};//常用停用词
publicstaticbooleanIsStopWord(Stringword)
{
for(inti=0;i<stopWordsList.length;++i)
{
if(word.equalsIgnoreCase(stopWordsList[i]))
returntrue;
}
returnfalse;
}
}
训练集管理器
我们的系统首先需要从训练样本集中得到假设的先验概率和给定假设下观察到不同数据的概率。
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->packagecom.vista;
importjava.io.BufferedReader;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileNotFoundException;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.util.Properties;
importjava.util.logging.Level;
importjava.util.logging.Logger;
/**
*训练集管理器
*/
publicclassTrainingDataManager
{
privateString[]traningFileClassifications;//训练语料分类集合
privateFiletraningTextDir;//训练语料存放目录
privatestaticStringdefaultPath="D://TrainningSet";
publicTrainingDataManager()
{
traningTextDir=newFile(defaultPath);
if(!traningTextDir.isDirectory())
{
thrownewIllegalArgumentException("训练语料库搜索失败!["+defaultPath+"]");
}
this.traningFileClassifications=traningTextDir.list();
}
/**
*返回训练文本类别,这个类别就是目录名
*@return训练文本类别
*/
publicString[]getTraningClassifications()
{
returnthis.traningFileClassifications;
}
/**
*根据训练文本类别返回这个类别下的所有训练文本路径(fullpath)
*@paramclassification给定的分类
*@return给定分类下所有文件的路径(fullpath)
*/
publicString[]getFilesPath(Stringclassification)
{
FileclassDir=newFile(traningTextDir.getPath()+File.separator+classification);
String[]ret=classDir.list();
for(inti=0;i<ret.length;i++)
{
ret[i]=traningTextDir.getPath()+File.separator+classification+File.separator+ret[i];
}
returnret;
}
/**
*返回给定路径的文本文件内容
*@paramfilePath给定的文本文件路径
*@return文本内容
*@throwsjava.io.FileNotFoundException
*@throwsjava.io.IOException
*/
publicstaticStringgetText(StringfilePath)throwsFileNotFoundException,IOException
{
InputStreamReaderisReader=newInputStreamReader(newFileInputStream(filePath),"GBK");
BufferedReaderreader=newBufferedReader(isReader);
Stringaline;
StringBuildersb=newStringBuilder();
while((aline=reader.readLine())!=null)
{
sb.append(aline+"");
}
isReader.close();
reader.close();
returnsb.toString();
}
/**
*返回训练文本集中所有的文本数目
*@return训练文本集中所有的文本数目
*/
publicintgetTrainingFileCount()
{
intret=0;
for(inti=0;i<traningFileClassifications.length;i++)
{
ret+=getTrainingFileCountOfClassification(traningFileClassifications[i]);
}
returnret;
}
/**
*返回训练文本集中在给定分类下的训练文本数目
*@paramclassification给定的分类
*@return训练文本集中在给定分类下的训练文本数目
*/
publicintgetTrainingFileCountOfClassification(Stringclassification)
{
FileclassDir=newFile(traningTextDir.getPath()+File.separator+classification);
returnclassDir.list().length;
}
/**
*返回给定分类中包含关键字/词的训练文本的数目
*@paramclassification给定的分类
*@paramkey给定的关键字/词
*@return给定分类中包含关键字/词的训练文本的数目
*/
publicintgetCountContainKeyOfClassification(Stringclassification,Stringkey)
{
intret=0;
try
{
String[]filePath=getFilesPath(classification);
for(intj=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);
}
returnret;
}
}
先验概率
先验概率是我们需要计算的两大概率值之一
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->packagecom.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表示训练文本集总数量。
*/
publicclassPriorProbability
{
privatestaticTrainingDataManagertdm=newTrainingDataManager();
/**
*先验概率
*@paramc给定的分类
*@return给定条件下的先验概率
*/
publicstaticfloatcalculatePc(Stringc)
{
floatret=0F;
floatNc=tdm.getTrainingFileCountOfClassification(c);
floatN=tdm.getTrainingFileCount();
ret=Nc/N;
returnret;
}
}
分类条件概率
这是另一个影响因子,和先验概率一起来决定最终结果
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->packagecom.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发生的条件概率。
*/
publicclassClassConditionalProbability
{
privatestaticTrainingDataManagertdm=newTrainingDataManager();
privatestaticfinalfloatM=0F;
/**
*计算类条件概率
*@paramx给定的文本属性
*@paramc给定的分类
*@return给定条件下的类条件概率
*/
publicstaticfloatcalculatePxc(Stringx,Stringc)
{
floatret=0F;
floatNxc=tdm.getCountContainKeyOfClassification(c,x);
floatNc=tdm.getTrainingFileCountOfClassification(c);
floatV=tdm.getTraningClassifications().length;
ret=(Nxc+1)/(Nc+M+V);//为了避免出现0这样极端情况,进行加权处理
returnret;
}
}
分类结果
用来保存各个分类及其计算出的概率值,
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->packagecom.vista;
/**
*分类结果
*/
publicclassClassifyResult
{
publicdoubleprobility;//分类的概率
publicStringclassification;//分类
publicClassifyResult()
{
this.probility=0;
this.classification=null;
}
}
朴素贝叶斯分类器
利用样本数据集计算先验概率和各个文本向量属性在分类中的条件概率,从而计算出各个概率值,最后对各个概率值进行排序,选出最大的概率值,即为所属的分类。
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->
packagecom.vista;
importcom.vista.ChineseSpliter;
importcom.vista.ClassConditionalProbability;
importcom.vista.PriorProbability;
importcom.vista.TrainingDataManager;
importcom.vista.StopWordsHandler;
importjava.util.ArrayList;
importjava.util.Comparator;
importjava.util.List;
importjava.util.Vector;
/**
*朴素贝叶斯分类器
*/
publicclassBayesClassifier
{
privateTrainingDataManagertdm;//训练集管理器
privateStringtrainnigDataPath;//训练集路径
privatestaticdoublezoomFactor=10.0f;
/**
*默认的构造器,初始化训练集
*/
publicBayesClassifier()
{
tdm=newTrainingDataManager();
}
/**
*计算给定的文本属性向量X在给定的分类Cj中的类条件概率
*<code>ClassConditionalProbability</code>连乘值
*@paramX给定的文本属性向量
*@paramCj给定的类别
*@return分类条件概率连乘值,即<br>
*/
floatcalcProd(String[]X,StringCj)
{
floatret=1.0F;
//类条件概率连乘
for(inti=0;i<X.length;i++)
{
StringXi=X[i];
//因为结果过小,因此在连乘之前放大10倍,这对最终结果并无影响,因为我们只是比较概率大小而已
ret*=ClassConditionalProbability.calculatePxc(Xi,Cj)*zoomFactor;
}
//再乘以先验概率
ret*=PriorProbability.calculatePc(Cj);
returnret;
}
/**
*去掉停用词
*@paramtext给定的文本
*@return去停用词后结果
*/
publicString[]DropStopWords(String[]oldWords)
{
Vector<String>v1=newVector<String>();
for(inti=0;i<oldWords.length;++i)
{
if(StopWordsHandler.IsStopWord(oldWords[i])==false)
{//不是停用词
v1.add(oldWords[i]);
}
}
String[]newWords=newString[v1.size()];
v1.toArray(newWords);
returnnewWords;
}
/**
*对给定的文本进行分类
*@paramtext给定的文本
*@return分类结果
*/
@SuppressWarnings("unchecked")
publicStringclassify(Stringtext)
{
String[]terms=null;
terms=ChineseSpliter.split(text,"").split("");//中文分词处理(分词后结果可能还包含有停用词)
terms=DropStopWords(terms);//去掉停用词,以免影响分类
String[]Classes=tdm.getTraningClassifications();//分类
floatprobility=0.0F;
List<ClassifyResult>crs=newArrayList<ClassifyResult>();//分类结果
for(inti=0;i<Classes.length;i++)
{
StringCi=Classes[i];//第i个分类
probility=calcProd(terms,Ci);//计算给定的文本属性向量terms在给定的分类Ci中的分类条件概率
//保存分类结果
ClassifyResultcr=newClassifyResult();
cr.classification=Ci;//分类
cr.probility=probility;//关键字在分类的条件概率
System.out.println("Inprocess.");
System.out.println(Ci+":"+probility);
crs.add(cr);
}
//对最后概率结果进行排序
java.util.Collections.sort(crs,newComparator()
{
publicintcompare(finalObjecto1,finalObjecto2)
{
finalClassifyResultm1=(ClassifyResult)o1;
finalClassifyResultm2=(ClassifyResult)o2;
finaldoubleret=m1.probility-m2.probility;
if(ret<0)
{
return1;
}
else
{
return-1;
}
}
});
//返回概率最大的分类
returncrs.get(0).classification;
}
publicstaticvoidmain(String[]args)
{
Stringtext="微软公司提出以446亿美元的价格收购雅虎中国网2月1日报道美联社消息,微软公司提出以446亿美元现金加股票的价格收购搜索网站雅虎公司。微软提出以每股31美元的价格收购雅虎。微软的收购报价较雅虎1月31日的收盘价19.18美元溢价62%。微软公司称雅虎公司的股东可以选择以现金或股票进行交易。微软和雅虎公司在2006年底和2007年初已在寻求双方合作。而近两年,雅虎一直处于困境:市场份额下滑、运营业绩不佳、股价大幅下跌。对于力图在互联网市场有所作为的微软来说,收购雅虎无疑是一条捷径,因为双方具有非常强的互补性。(小桥)";
BayesClassifierclassifier=newBayesClassifier();//构造Bayes分类器
Stringresult=classifier.classify(text);//进行分类
System.out.println("此项属于["+result+"]");
}
}
训练集与分类测试
作为测试,这里选用Sogou实验室的文本分类数据,我只使用了mini版本。迷你版本有10个类别 ,共计100篇文章,总大小244KB
使用的测试文本:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->微软公司提出以446亿美元的价格收购雅虎
中国网2月1日报道美联社消息,微软公司提出以446亿美元现金加股票的价格收购搜索网站雅虎公司。
微软提出以每股31美元的价格收购雅虎。微软的收购报价较雅虎1月31日的收盘价19.18美元溢价62%。微软公司称雅虎公司的股东可以选择以现金或股票进行交易。
微软和雅虎公司在2006年底和2007年初已在寻求双方合作。而近两年,雅虎一直处于困境:市场份额下滑、运营业绩不佳、股价大幅下跌。对于力图在互联网市场有所作为的微软来说,收购雅虎无疑是一条捷径,因为双方具有非常强的互补性。(小桥)
使用mini版本的测试结果:
分享到:
相关推荐
基于朴素贝叶斯分类器的文本分类算法(C语言).doc
朴素贝叶斯模型是文本分类模型中的一种简单但性能优越的的分类模型。为了简化计算过程,假定各待分类文本特征变量是相互独立的,即“朴素贝叶斯模型的假设”。相互独立表明了所有特征变量之间的表述是没有关联的。
基于朴素贝叶斯分类器的文本分类程序 python
朴素贝叶斯分类器的文本分类算法
基于朴素贝叶斯分类器的文本分类算法(C语言)
基于权重的朴素贝叶斯分类器设计与实现 论文
基于朴素贝叶斯分类器的文本分类算法(C语言).rar
在特征独立性假设的基础上, 讨论了朴素贝叶斯分类器的原理, 以及训练朴素贝叶斯分类器和应用朴素贝叶斯分类器进行分类的问题。
朴素贝叶斯算法文本分类JAVA实现
贝叶斯是一种基于概率的学习算法,能够用来计算显式的假设概率,它基于假设的先验概率,给定假设下观察到不同数据的概率以及观察到的数据本身
该算法用Python实现了朴素贝叶斯分类器,并用于文本分类,实现垃圾邮件的检测。
实验要求 文本类别数:>=10类。 训练集文档数:>=500000篇;每类平均50000篇。...自行实现朴素贝叶斯,训练文本分类器。 对测试集的文本进行分类 对测试集的分类结果利用正确率和召回率进行分析评价。
朴素贝叶斯 分类算法数据集文本挖掘(Text Mining,从文字中获取信息)是一个比较宽泛的概念,这一技术在如今每天都有海量文本数据生成的时代越来越受到关注。目前,在机器学习模型的帮助下,包括情绪分析,文件分类...
代码:Java语言 算法:朴素贝叶斯分类器(中文)适用于情感分析 涉及:条件概率,先验概率计算,中文分词器,停用词处理
使用朴素贝叶斯方法实现的中文文本分类算法
常见的朴素贝叶斯分类器有多项式朴素贝叶斯、伯努利朴素贝叶斯和高斯朴素贝叶斯等。 5. 模型评估: 使用测试数据集评估模型的性能,常见的评估指标包括准确率、召回率、精确率和F1值等。 下面是一个简单的Python...
人工智能大作业,文本分类,TF-IDF+手写朴素贝叶斯。本项目利用分类算法实现对文本的数据挖掘,主要包括:1. 语料库的构建,主要从搜狗语料库、复旦大学中文语料库等搜集文章作为...朴素贝叶斯分类器要手动编写完成。
1:用MapReduce算法实现贝叶斯分类器的训练过程,并输出训练模型; 2:用输出的模型对测试集文档进行分类测试。测试过程可基于单机Java程序,也可以是MapReduce程序。输出每个测试文档的分类结果; 3:利用测试...
常见的朴素贝叶斯分类器有多项式朴素贝叶斯、伯努利朴素贝叶斯和高斯朴素贝叶斯等。可以使用scikit-learn库中的相关类来实现。 5. 模型评估: 使用测试数据集评估模型的性能,常见的评估指标包括准确率、召回率、...
# 基于Hadoop的朴素贝叶斯分类(MapReduce实现) 该项目为Hadoop课程项目,基于MapReduce设计朴素贝叶斯文本分类器,并评估分类结果。 以下简单介绍项目内容与运行说明: ## 项目内容 1. 用MapReduce算法实现贝叶斯...