技术/笔记/MapReduce实战
MapReduce 实现贝叶斯分类器
理论基础
朴素贝叶斯公式求后验概率
其中 为文档, 为分类。文档是词的合集,提取特征 ,即文档由n个词 token(可重复)组成。做独立性假设后公式可化简为:
由于需要知道的是文档最有可能的分类,因此实际上是求 ,又因为 不变,因此也就是求:
用词 在类别 的文档中的占比来估计, 用类别 的文档在所有文档中比重来估计。并且为了避免个别 导致错误,对单词频数加1进行平滑:
\hat{P}(t_j|c_i) & = \frac{N(t=t_j,\space c=c_i)+1}{\sum_{t_k \in V_i} (N(t=t_k,\space c=c_i)+1)} \\ & = \frac{N(t=t_j,\space c=c_i)+1}{N(c=c_i)+|V_i|}
其中 为 类文章中 出现的次数, 为出现在所有类型为 的文档中的单词集合(不重复), 为不重复单词数。
整体框架
- 
Job1:统计 - 输入训练集(分好类的文档,不同类别的文档在不同的目录中,目录名即为类别名)
- Mapper<Text, Writable, Text, Writable>- 使用自定义的InputFormat,只读取文件所在目录名而不读取内容,并且规定split不会切分文件,防止统计冗余
- k1=k2:继承InputFormat的输出键值对,类别名=目录名
- v1=v2:1
 
- 使用自定义的
- Reducer<Text, List<Writable>- 输出 <类别, 总数>
 
- 输出 
 
- 
Job2:统计 - 输入训练集
- Mapper<LongWritable, Text, Text, IntWritable>- 使用默认的TextInputFormat
- RecordReader按行读取(使用- TextInputFormat),一行一个单词,同时读取split包含的文件名作为类别,将类别和单词用- -拼接成一个Text类型变量作为Key输出
- Value 输出取 1即可
 
- 使用默认的
- Reducer< Text, List<IntWritable> >- 输出< 类别-单词, 总数 >
 
- 输出
 
- 
Job3: 统计 - 
输入job2的output 
- 
Mapper<Text, IntWritable>- RecordReader 读入每一行,Map成<类别,个数>
 
- RecordReader 读入每一行,Map成
- 
Reducer 输入 <类别, list{个数}>,输出<类别, 个数求和>
 
- 
- 
Job3:测试 - 输入测试集(待分类的文档)
- 输出文档类别
- 评估分类效果
 
环境准备
安装 Hadoop
- 官网给的都是基于 Linux 系统构建的,如果要在 Windows 系统上使用,需要补全 bin 中的winutils.exe,hadoop.dll等文件- 或者下载源码,按照说明自己在 Windows 上构建
 
- 需要指定相应版本的 JDK (一般都是 Java 8)
- 正确设置环境变量 %HADOOP_HOME%- 使用 Cygwin环境执行 Hadoop 命令会产生路径问题,导致无法正确加载类
 
- 使用 
启用 Hadoop 环境
- 注意启用 SSH Server 服务
| 1 |  | 
- 
运行相应的启动脚本以启动 Hadoop 相应服务: $ hadoop-3.3.5\sbin\start-xxx.cmd- 例如启动 hdfs 则执行 sbin\start-dfs.cmd
- 注意使用管理员权限运行 Shell
 
- 例如启动 hdfs 则执行 
- 
Win 下使用 hdfs dfs命令行的-put和-get命令时,指定本地路径时不能使用相对路径
- 
开启dfs后无法写入:离开NameNode安全模式 hdfs dfsadmin -safemode leave
数据准备
- 选择NBCorpus\Country\AUSTR、NBCorpus\Country\BRAZ和BCorpus\Country\CANA三个目录中的文件作为训练数据,分类的class为AUSTER和CANA
- 编写python脚本,按照8:2的比例划分训练集和测试集,并存入hdfs
| 类别 | 训练集数目 | 测试集数目 | 
|---|---|---|
| AUSTR | 244 | 61 | 
| BRAZ | 160 | 40 | 
| CANA | 211 | 52 | 
程序编写
- 主要编写两个 Java 文件,一个是 MapReduce 程序 NaiveBayes.java,实现朴素贝叶斯分类器算法。另一个是本地控制台程序Predictor.java,根据测试集预测并输出评估指标。
- NaiveBayes.java实现三个 job,输入分好词的文件(训练集),以文本形式将统计结果输出到三个文件夹中。
- Predictor.java根据测试集文件夹内容对每个文件进行预测,产生混淆矩阵,并计算每个类别对应的 Precision、Recall和F1值,最后还会输出指标平均值。
编译运行
- 执行以下命令编译 NaiveBayes.java文件(或者在IDEA中编译),获得一系列字节码文件NaiveBayes*.class
| 1 |  | 
- 打包 jar 并部署到 hadoop 运行
| 1 |  | 
- 将输出结果复制到本地
| 1 |  | 
- 三个 job 的输出结果预览如下所示
| 1 |  | 
| 1 |  | 
| 1 |  | 
- IDEA下编译运行 Predictor.java查看预测结果
实验结果
预测评估
- Predictor 的控制台输出如下,从上到下依次是混淆矩阵、各个类别的 Precision、Recall和F1分数,最后是均值。

