构建基于JAVA的朴素贝叶斯文本分类器

时间:2022-04-26
本文章向大家介绍构建基于JAVA的朴素贝叶斯文本分类器,主要内容包括基于Java实现朴素贝叶斯、2. NaiveBayesKnowledgeBase对象、3.Document对象、4. FeatureStats对象、5. FeatureExtraction类、6. TextTokenizer类、使用基于JAVA实现的NaiveBayes类、必要的补充、2.文本预处理:、3.其他朴素贝叶斯模型:、4.附加的特征选择方法:、5.性能优化:、马上来了...最后的笔记!、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

在前面的文章中,我们讨论了朴素贝叶斯文本分类器的理论背景以及在文本分类中使用特征选择技术的重要性。在本文中,我们将结合两种方法,用JAVA简单实现朴素贝叶斯文本分类算法。你可以Github上下载分类器的开源代码,代码遵守GPL v3(通用公共许可证第三版草案)。

更新:现在Datumbox机器学习框架开源,可以免费下载。用Java实现朴素贝叶斯分类器的源码在com.datumbox.framework.machinelearning.classification包中。

基于Java实现朴素贝叶斯

代码用JAVA编写,可以直接从Github下载。该代码遵循GPL v3(通用公共许可证第三版草案),你可以随意地使用、修改或重新发布代码。

本文的文本分类器结合了多项式朴素贝叶斯模型Chisquare特征选择算法,这两种方法均在之前的文章中有所介绍。另外,通过javadoc命令生成的开发文档可以在源代码中找到。因此,在这里,我将从重点介绍分类器的体系结构的抽象化。

1. NaiveBayes类

这个类是文本分类器的主体部分,实现了一些训练分类器并进行预测的方法,如train()和predict()。另外,在训练和预测过程之前,这个类也可以调用适当的外部方法对数据进行预处理。

2. NaiveBayesKnowledgeBase对象

训练过程的输出结果为NaiveBayesKnowledgeBase对象,其存储着朴素贝叶斯分类器中所有必要的信息和概率。

3.Document对象

代码中的训练文本和测试文本都存储为Document对象的形式,另外,Document对象含有文档中的所有词条(单词)、统计信息和文档的目标分类信息。

4. FeatureStats对象

FeatureStats对象存储着特征提取过程中生成的一些统计信息,其中包含:特征和类的联合计数(联合概率和似然估计)、类别计数(该项为空时,使用先验概率)以及用于训练的样本总数。

5. FeatureExtraction类

该类用于特征提取。需要注意的是,由于这个类中计算了分类算法的后面阶段需要的几个统计量,为了避免重复计算,这些统计量会缓存到FeatureStats对象中。

6. TextTokenizer类

这是一个简单文本标记类,负责将初始文本进行预处理、清除和标记,并将其转换为Document对象。

使用基于JAVA实现的NaiveBayes类

NaiveBayesExample类提供了一个使用NaiveBayes类的示例,训练了一个用于检测文本语言的简单朴素贝叶斯分类器。为了训练分类器,我们一开始在HashMap中存储训练数据集的路径,然后加载数据集内容。

//数据集文件的map接口
Map<String, URL> trainingFiles = new HashMap<>();
trainingFiles.put("English", NaiveBayesExample.class.getResource("/datasets/training.language.en.txt"));
trainingFiles.put("French", NaiveBayesExample.class.getResource("/datasets/training.language.fr.txt"));
trainingFiles.put("German", NaiveBayesExample.class.getResource("/datasets/training.language.de.txt"));

//在内存中加载示例
Map<String, String[]> trainingExamples = new HashMap<>();
for(Map.Entry<String, URL> entry : trainingFiles.entrySet()) {
   trainingExamples.put(entry.getKey(), readLines(entry.getValue()));
}

我们调用数据来训练下面的NaiveBayes分类器,训练完成后,把结果存储到NaiveBayesKnowledgeBase对象备用。

//训练分类器
NaiveBayes nb = new NaiveBayes();
nb.setChisquareCriticalValue(6.63); //假设检验中的假定值为0.01
nb.train(trainingExamples);

//得到经过训练的分类器
NaiveBayesKnowledgeBase knowledgeBase = nb.getKnowledgeBase();

最后,要使用分类器来预测新样本的分类,你需要调用前面训练得到的NaiveBayesKnowledgeBase对象,来初始化分类器。然后调用predict()方法,便可以预测文档的分类。

//文本分类器
nb = new NaiveBayes(knowledgeBase);
String exampleEn = "I am English";
String outputEn = nb.predict(exampleEn);
System.out.format("The sentense "%s" was classified as "%s".%n", exampleEn, outputEn);

必要的补充

值得注意的是,对于复杂的文本分类问题,本文实现的分类器不是完备的解决方案。以下补充了一些可行操作:

1.关键词提取:

对于简单的分类问题,如语言检测,在算法中使用单个关键字是可行的。但是,面对其他更为复杂的问题,我们需要提取文本的n元模型单词序列。因此,要么修改TextTokenizer.extractKeywords()方法以适应复杂文本分类问题,要么使用Datumbox的Keyword Extraction API函数来获得文档的所有n元单词序列(关键字组合)。

2.文本预处理:

在使用分类器之前,为了删除不必要的字符/部分,我们通常需要对文档进行预处理。虽然我们已经通过使用TextTokenizer.preprocess()方法执行了一定的预处理操作,但如果在使用分类器前不预处理,那么在分析HTML页面时,会遇到许多麻烦。我们可以简单地修剪掉HTML标签,只保留文档的纯文本,或者使用更完善的机器学习技术来检测页面的主要文本,并去除页脚、标题菜单等内容。若是第二种方法,我们可以借助Datumbox的Text Extraction API函数。

3.其他朴素贝叶斯模型:

目前的分类器实现了多项式朴素贝叶斯分类器模型,但正如我们之前在情感分析这篇文章中所说的,不同的分类问题需要不同的模型。在一些问题中,二值化多项式模型更为适用,而在其他一些问题中,伯努利模型表现得更好。你可以以本文实现的例子为起点,结合朴素贝叶斯教程的指导,自己实现其他模型。

4.附加的特征选择方法:

为了给分类器选择最合适的特征,本程序使用了Chisquare特征选择算法。正如前文所述,Chisquare特征选择方法是一种很棒的技术,依靠统计信息来选择适当的特征,但倾向于选择那些仅在某个类别中出现的稀有特征。所以,在进行特征选择或实现其他方法(如上述文章中讨论的互信息)之前,我们可以先消除噪声性/稀有特征。

5.性能优化:

在编写程序时,提高代码的可读性比对代码执行微小优化更为重要。尽管这样的优化让代码更难以阅读/维护,但是这通常是十分必要的操作。因为在训练和测试期间,该算法中的许多循环运行了数百万次。以这个实现的分类器为起点,你可以更方便地开发自己的调试版本。

马上来了...最后的笔记!

为了充分理解程序的工作原理,强烈建议阅读前面两篇关于朴素贝叶斯分类器特征选择的文章。你将了解这些方法的理论背景,并能更透彻地理解算法/代码。

我们应该注意到,虽然朴素贝叶斯简单而高效,且在大部分情况下都“相当准确”,但由于假定了特征的条件独立性,该分类器还是“朴素的”。由于在文本分类问题中这种假设几乎从未成真,朴素贝叶斯几乎从来都不是表现最好的分类器。在Datumbox API中,标准朴素贝叶斯分类器的几种延伸模型仅用于如语言检测之类的简单问题。对于更为复杂的文本分类问题,我们需要使用更高级的技术,如最大熵分类器