Preface
文本的分类和聚类是一个比较有意思的话题,我以前也写过一篇blog《基于K-Means的文本聚类算法》,加上最近读了几本数据挖掘和机器学习的书籍,因此很想写点东西来记录下学习的所得。
在本文的上半部分《基于朴素贝叶斯分类器的文本分类算法(上)》一文中简单介绍了贝叶斯学习的基本理论,这一篇将展示如何将该理论运用到中文文本分类中来,具体的文本分类原理就不再介绍了,在上半部分有,也可以参见代码的注释。
文本特征向量
文本特征向量可以描述为文本中的字/词构成的属性。例如给出文本:
Good good study,Day day up.
可以获得该文本的特征向量集:{ Good, good, study, Day, day , up.}
朴素贝叶斯模型是文本分类模型中的一种简单但性能优越的的分类模型。为了简化计算过程,假定各待分类文本特征变量是相互独立的,即“朴素贝叶斯模型的假设”。相互独立表明了所有特征变量之间的表述是没有关联的。如上例中,[good]和[study]这两个特征变量就是没有任何关联的。
在上例中,文本是英文,但由于中文本身是没有自然分割符(如空格之类符号),所以要获得中文文本的特征变量向量首先需要对文本进行中文分词。
中文分词 这里采用极易中文分词组件,这个中文分词组件可以免费使用,提供Lucene接口,跨平台,性能可靠。
停用词处理 去掉文档中无意思的词语也是必须的一项工作,这里简单的定义了一些常见的停用词,并根据这些常用停用词在分词时进行判断。
训练集管理器 我们的系统首先需要从训练样本集中得到假设的先验概率和给定假设下观察到不同数据的概率。
先验概率 先验概率是我们需要计算的两大概率值之一 分类条件概率 这是另一个影响因子,和先验概率一起来决定最终结果 分类结果 用来保存各个分类及其计算出的概率值,
朴素贝叶斯分类器 利用样本数据集计算先验概率和各个文本向量属性在分类中的条件概率,从而计算出各个概率值,最后对各个概率值进行排序,选出最大的概率值,即为所属的分类。
package com.vista;
import java.io.IOException;
import jeasy.analysis.MMAnalyzer;
/**
* 中文分词器
*/
public class ChineseSpliter
{
/**
* 对给定的文本进行中文分词
* @param text 给定的文本
* @param splitToken 用于分割的标记,如"|"
* @return 分词完毕的文本
*/
public static String split(String text,String splitToken)
{
String result = null;
MMAnalyzer analyzer = new MMAnalyzer();
try
{
result = analyzer.segment(text, splitToken);
}
catch (IOException e)
{
e.printStackTrace();
}
return result;
}
}
package com.vista;
/**
* 停用词处理器
* @author phinecos
*
*/
public class StopWordsHandler
{
private static String stopWordsList[] ={"的", "我们","要","自己","之","将","“","”",",","(",")","后","应","到","某","后","个","是","位","新","一","两","在","中","或","有","更","好",""};//常用停用词
public static boolean IsStopWord(String word)
{
for(int i=0;i<stopWordsList.length;++i)
{
if(word.equalsIgnoreCase(stopWordsList[i]))
return true;
}
return false;
}
}
package com.vista;
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;
/**
* 训练集管理器
*/
public class TrainingDataManager
{
private String[] traningFileClassifications;//训练语料分类集合
private File traningTextDir;//训练语料存放目录
private static String defaultPath = "D:\\TrainningSet";
public TrainingDataManager()
{
traningTextDir = new File(defaultPath);
if (!traningTextDir.isDirectory())
{
throw new IllegalArgumentException("训练语料库搜索失败! [" +defaultPath + "]");
}
this.traningFileClassifications = traningTextDir.list();
}
/**
* 返回训练文本类别,这个类别就是目录名
* @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;
}
}
package com.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表示训练文本集总数量。
*/
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;
}
}
package com.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发生的条件概率。
*/
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); //为了避免出现0这样极端情况,进行加权处理
return ret;
}
}
package com.vista;
/**
* 分类结果
*/
public class ClassifyResult
{
public double probility;//分类的概率
public String classification;//分类
public ClassifyResult()
{
this.probility = 0;
this.classification = null;
}
}
package com.vista;
import com.vista.ChineseSpliter;
import com.vista.ClassConditionalProbability;
import com.vista.PriorProbability;
import com.vista.TrainingDataManager;
import com.vista.StopWordsHandler;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Vector;
/**
* 朴素贝叶斯分类器
*/
public class BayesClassifier
{
private TrainingDataManager tdm;//训练集管理器
private String trainnigDataPath;//训练集路径
private static double zoomFactor = 10.0f;
/**
* 默认的构造器,初始化训练集
*/
public BayesClassifier()
{
tdm =new TrainingDataManager();
}
/**
* 计算给定的文本属性向量X在给定的分类Cj中的类条件概率
* <code>ClassConditionalProbability</code>连乘值
* @param X 给定的文本属性向量
* @param Cj 给定的类别
* @return 分类条件概率连乘值,即<br>
*/
float calcProd(String[] X, String Cj)
{
float ret = 1.0F;
// 类条件概率连乘
for (int i = 0; i <X.length; i++)
{
String Xi = X[i];
//因为结果过小,因此在连乘之前放大10倍,这对最终结果并无影响,因为我们只是比较概率大小而已
ret *=ClassConditionalProbability.calculatePxc(Xi, Cj)*zoomFactor;
}
// 再乘以先验概率
ret *= PriorProbability.calculatePc(Cj);
return ret;
}
/**
* 去掉停用词
* @param text 给定的文本
* @return 去停用词后结果
*/
public String[] DropStopWords(String[] oldWords)
{
Vector<String> v1 = new Vector<String>();
for(int i=0;i<oldWords.length;++i)
{
if(StopWordsHandler.IsStopWord(oldWords[i])==false)
{//不是停用词
v1.add(oldWords[i]);
}
}
String[] newWords = new String[v1.size()];
v1.toArray(newWords);
return newWords;
}
/**
* 对给定的文本进行分类
* @param text 给定的文本
* @return 分类结果
*/
@SuppressWarnings("unchecked")
public String classify(String text)
{
String[] terms = null;
terms= ChineseSpliter.split(text, " ").split(" ");//中文分词处理(分词后结果可能还包含有停用词)
terms = DropStopWords(terms);//去掉停用词,以免影响分类
String[] Classes = tdm.getTraningClassifications();//分类
float probility = 0.0F;
List<ClassifyResult> crs = new ArrayList<ClassifyResult>();//分类结果
for (int i = 0; i <Classes.length; i++)
{
String Ci = Classes[i];//第i个分类
probility = calcProd(terms, Ci);//计算给定的文本属性向量terms在给定的分类Ci中的分类条件概率
//保存分类结果
ClassifyResult cr = new ClassifyResult();
cr.classification = Ci;//分类
cr.probility = probility;//关键字在分类的条件概率
System.out.println("In process.");
System.out.println(Ci + ":" + probility);
crs.add(cr);
}
//对最后概率结果进行排序
java.util.Collections.sort(crs,new Comparator()
{
public int compare(final Object o1,final Object o2)
{
final ClassifyResult m1 = (ClassifyResult) o1;
final ClassifyResult m2 = (ClassifyResult) o2;
final double ret = m1.probility - m2.probility;
if (ret < 0)
{
return 1;
}
else
{
return -1;
}
}
});
//返回概率最大的分类
return crs.get(0).classification;
}
public static void main(String[] args)
{
String text = "微软公司提出以446亿美元的价格收购雅虎中国网2月1日报道 美联社消息,微软公司提出以446亿美元现金加股票的价格收购搜索网站雅虎公司。微软提出以每股31美元的价格收购雅虎。微软的收购报价较雅虎1月31日的收盘价19.18美元溢价62%。微软公司称雅虎公司的股东可以选择以现金或股票进行交易。微软和雅虎公司在2006年底和2007年初已在寻求双方合作。而近两年,雅虎一直处于困境:市场份额下滑、运营业绩不佳、股价大幅下跌。对于力图在互联网市场有所作为的微软来说,收购雅虎无疑是一条捷径,因为双方具有非常强的互补性。(小桥)";
BayesClassifier classifier = new BayesClassifier();//构造Bayes分类器
String result = classifier.classify(text);//进行分类
System.out.println("此项属于["+result+"]");
}
}
发表评论
-
基于朴素贝叶斯分类器的文本分类(一)
2012-09-07 14:59 2140Preface 本文缘起 ... -
方差大用
2012-06-27 14:17 795方差 方差(Variance) [] 什么 ... -
加权方法
2012-06-19 09:19 13711.TF-IDF: TF-IDF是一种统计方法,用以 ... -
文本分类KNN算法
2012-05-30 09:07 1821kNN算法简介: ... -
Hadamard Product
2012-05-11 09:36 1461Hadamard product (matrices) &l ... -
似然函数的理解
2012-05-11 09:36 2112在数理统计学中,似然函数是一种关于统计模型中的参数的函数,表示 ... -
贝叶斯分类的缺点
2012-05-09 16:50 1415由于贝叶斯定理假设一个属性值对给定类的影响独立于其它属性的值, ...
相关推荐
朴素贝叶斯(Naive Bayes)是一种基于概率论的机器学习算法,尤其在文本分类领域表现出色。它依赖于贝叶斯定理,并假设特征之间相互独立,这是其“朴素”的体现。在这个项目中,我们将深入探讨如何利用Python来实现...
朴素贝叶斯文本分类器是一种基于概率统计的机器学习算法,尤其在文本分类领域中广泛应用。这个特定的项目,"朴素贝叶斯文本分类器(新浪微博)"是针对新浪微博的数据进行情感分析,将微博内容分为积极和消极两类,...
《基于Hadoop实现朴素贝叶斯文本分类器》 在当今大数据时代,高效的数据处理和分析成为了企业竞争力的关键。Hadoop作为开源的分布式计算框架,以其高容错性、可扩展性和低成本的优势,广泛应用于海量数据的处理。而...
朴素贝叶斯分类器是一种基于概率的机器学习方法,它在文本分类领域有着广泛的应用。该模型基于贝叶斯定理,并且通过“朴素”这一假设来简化计算,即假设特征之间是相互独立的。这一假设使得朴素贝叶斯分类器能够高效...
朴素贝叶斯文本分类是一种广泛应用于自然语言处理领域的机器学习技术,主要用来对文本数据进行自动分类。在信息检索、垃圾邮件过滤、情感分析等多个场景中都有它的身影。该方法基于贝叶斯定理和特征条件独立假设,即...
朴素贝叶斯文本分类器是一种广泛应用的机器学习算法,尤其在自然语言处理领域,用于将文本数据归类到预定义的类别中。本程序的Java实现深入探讨了这一概念,并提供了完整的工具集,包括源代码、实验报告、可执行程序...
【基于Hadoop的分布式朴素贝叶斯文本分类】 在信息技术领域,随着互联网数据的爆炸性增长,传统的数据处理方法已无法满足对海量信息的管理和分析需求。云计算的出现,特别是Hadoop这一开源分布式系统框架,为解决大...
文件名“第18章 机器学习案例——基于朴素贝叶斯算法的文本分类”可能包含以下内容: 1. 数据集:包含各种文本和对应的类别标签,用于训练和测试模型。 2. 预处理脚本:用于清洗和转换文本数据,使其适合输入到模型...
朴素贝叶斯文本分类是一种基于概率的机器学习方法,常用于自然语言处理任务,如垃圾邮件过滤、情感分析和主题分类。在这个Java实现的项目中,我们可以通过详细注释理解算法的工作原理,并直接运行代码进行实践。 ...
朴素贝叶斯分类器是一种基于概率的机器学习算法,它基于贝叶斯定理和特征条件独立假设。在大数据处理领域,结合Hadoop框架可以实现大规模数据集的分类任务。Hadoop是一个开源分布式计算框架,它允许在大量廉价硬件上...
朴素贝叶斯文本分类器是基于朴素贝叶斯分类器的文本分类算法。朴素贝叶斯分类器是一个简单的概率分类器,它基于贝叶斯定理,假设在给定目标属性之间是相互独立的。 贝叶斯定理在分类中的应用: 在分类问题中,我们...
本主题将深入探讨“基于朴素贝叶斯的垃圾邮件分类”这一技术。 朴素贝叶斯分类器基于贝叶斯定理,该定理是概率论中的一个基础概念,用于计算事件发生的条件概率。在垃圾邮件分类中,假设每个词在邮件中出现的概率...
朴素贝叶斯算法是一种在机器学习领域广泛应用的概率型分类方法,尤其在文本分类中表现出色。这个程序是用Python语言实现的,它利用朴素贝叶斯理论对文本数据进行分类。下面将详细介绍朴素贝叶斯算法及其在Python中的...
朴素贝叶斯(Naive Bayes)是一种基于概率论的机器学习算法,尤其在文本分类领域表现出色。这个算法的核心思想是利用贝叶斯定理和特征条件独立假设来进行预测。下面将详细介绍朴素贝叶斯在文本分类中的应用及其工作...
朴素贝叶斯分类是一种基于概率的机器学习方法,它在数据分类中有着广泛的应用。该方法基于贝叶斯定理,假设特征之间相互独立,因此被称为“朴素”。在这个实例中,我们将探讨如何使用朴素贝叶斯分类器处理Iris数据集...
#清磁盘啦~,CSDN“网盘”真好用,感谢CSDN~ 机器学习,基于朴素贝叶斯机器学习算法实现对情感文本分析与分类(含数据集),sgns.weibo.bigram-char,使用gensim加载预训练中文分词