构建基于JAVA的朴素贝叶斯文本分类器
在前面的文章中,我们讨论了朴素贝叶斯文本分类器的理论背景以及在文本分类中使用特征选择技术的重要性。在本文中,我们将结合两种方法,用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中,标准朴素贝叶斯分类器的几种延伸模型仅用于如语言检测之类的简单问题。对于更为复杂的文本分类问题,我们需要使用更高级的技术,如最大熵分类器。
- Java关键字 Finally执行与break, continue, return等关键字的关系
- #if 和#ifdef的区别
- python高阶函数:map(f,[list]),reduce(f,[list],可选初始值),
- 深入探讨 Java 类加载器
- 斐波那契查找原理详解与实现
- 增量数据丢失的原因分析(二)(r8笔记第76天)
- pycharm 之模块与模块引用
- 判断栈的出栈顺序合法性
- Combination Sum II 组合数求和之2-Leetcode
- Combination Sum 组合数求和-Leetcode
- python 中输出字符的颜色控制属性
- 一则数据库无法重启的案例分析(r8笔记第96天)
- 最大公约数和最小公倍数及其应用(Go语言解法)
- JAVA private私有类的 默认构造函数 的生成过程
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- SSM第一讲 Spring概述和基础知识详解
- springBoot 入门(四)—— 使用 纯注解方式的junit整合测试
- ClassLoader工作机制
- SSM第三讲 SpringAOP开发
- 如何加载Class文件到JVM
- spring + maven 实现发送邮件
- SSM第四讲 Mybatis原理及开发流程
- SSM第五讲 动态SQL与高级查询
- SSM第六讲 MyBatis的高级特性
- SSM第七讲 SpringMVC概述和基础知识详解
- SSM第八讲 SpringMVC高级特性
- SSM第九讲 Spring+SpringMVC+MyBatis框架整合
- 大型项目技术栈第一讲 Vue.js的使用
- springBoot 入门(五)—— 使用 纯注解方式 的springboot+ mybatis+junit4 整合
- 常见加载类错误分析