技术/笔记/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分数,最后是均值。