Hadoop基于朴素贝叶斯分类器的情感判别实践

耗尽温柔 提交于 2020-01-15 04:42:27

1.基础材料说明

1)训练集training.txt文件

该文件是一个大小为75.8MB的文本数据集,并包含了20,000,000条数据记录,每行数据中包含的信息为“评价结论\t 评价内容”。其中,“评价内容”是若干词语组合而成,词语之间是空格隔开,词语包括中文、英文以及其他特殊符号,即其内容为“word1 word2 word3 word4 …… wordn”,其中wordi表示当前文本描述中的第i个词,n为当前文本描述中包含的总词数。

2)测试集test.txt文件
给定“test.data”数据集,该数据集包含了2000条记录,每行记录中包含的信息为“评价内容”,该“评价内容”的具体表现形式与前文描述的“training.txt”数据集相同。

3)文件命名说明
本工程实践为课程作业,故项目名为NB_2017082040,HDFS储存路径为hdfs://master:9000/input_2017082040/training.txt。

4)运行环境说明
编译器:eclipse-jee-2019-12-R-linux-gtk-x86_64.tar.gz
Hadoop:Hadoop 2.7.7

2.实现过程

2.1 上传文件至HDFS

hadoop fs -put /root/Documents/training.txt hdfs://master:9000/input/training.txt

2.2 创建工程

基于Eclipse并使用Maven创建Hadoop工程。Maven配置过程略。创建Maven项目后修改pom.xml文件。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>Hadoop</groupId>
  <artifactId>NB_2017082040</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>NB_2017082040</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.7.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.7.7</version>
        </dependency>
  </dependencies>
</project>

2.3 训练模型

通过MapReduce实现数据清洗和取词建立训练模型
关键代码

package Hadoop.NB_2017082040;

import java.io.IOException;
import java.util.regex.Pattern;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

public class feelMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
	private final IntWritable one = new IntWritable(1);

	public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
		String data = value.toString();
		// 获得每行文档内容,进行拆分
		String content[] = data.split("\t", 2);
		// 获取情感标签:content[0]
		String label = content[0];
		// 获取当前行的特征
		String features[] = content[1].split(" ");
		// 清洗数据并统计
		for (String feature : features) {
			// 清洗数据
			if (Pattern.matches("[\u4e00-\u9fa5]+", feature)) {
				// 输出一次该类别下特征计数
				context.write(new Text(label + "_" + feature), one);
			}
		}
		// 输出情感标签
		context.write(new Text(label), one);
	}
}
package Hadoop.NB_2017082040;

import java.io.IOException;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class feelReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
	public void reduce(Text key, Iterable<IntWritable> values, Context context)
			throws IOException, InterruptedException {
		int count = 0;
		for (IntWritable val : values) {
			count += val.get();
		}
		context.write(key, new IntWritable(count));
	}
}

2.4 朴素贝叶斯实现

朴素贝叶斯采用多项式模型,拉普拉斯平滑减少误差,具体可自行百度。
关键算法实现

	/**
	 * 预测模型采用多项式模型
	 */
	private static String modelFilePath = "/root/Documents/2017082040_模型.txt";
	private static String testDataFilePath = "/root/Documents/test.txt";
	public static HashMap<String, Integer> parameters = null; // 情感标签集
	public static double Nd = 0.;// 文件中的总记录数
	public static HashMap<String, Integer> allFeatures = null;// 整个训练样本的键值对
	public static HashMap<String, Double> labelFeatures = null;// 某一类别下所有词出现的总数
	public static HashSet<String> V = null;// 总训练样本的不重复单词

	/**
	 * 对训练数据进行二次处理,得到多项式模型
	 */
	public static void loadModel(String modelFile) throws Exception {
		if (parameters != null && allFeatures != null) {
			return;
		}
		parameters = new HashMap<String, Integer>();// 情感标签集
		allFeatures = new HashMap<String, Integer>();// 全部属性对
		labelFeatures = new HashMap<String, Double>();// 某一类别下所有词出现的总数
		V = new HashSet<String>();
		BufferedReader br = new BufferedReader(new FileReader(modelFile));
		String line = null;
		while ((line = br.readLine()) != null) {
			String feature = line.substring(0, line.indexOf("\t"));
			Integer count = Integer.parseInt(line.substring(line.indexOf("\t") + 1));
			if (feature.contains("_")) {
				allFeatures.put(feature, count);
				String label = feature.substring(0, feature.indexOf("_"));
				if (labelFeatures.containsKey(label)) {
					labelFeatures.put(label, labelFeatures.get(label) + count);
				} else {
					labelFeatures.put(label, (double) count);
				}
				String word = feature.substring(feature.indexOf("_") + 1);
				if (!V.contains(word)) {
					V.add(word);
				}
			} else {
				parameters.put(feature, count);
				Nd += count;
			}
		}
		br.close();
	}

	/**
	 * 计算条件概率
	 */
	public static String predict(String sentence, String modelFile) throws Exception {
		loadModel(modelFile);
		String predLabel = null;
		double maxValue = Double.NEGATIVE_INFINITY;// 最大类概率(默认值为负无穷小)
		String[] words = sentence.split(" ");
		Set<String> labelSet = parameters.keySet(); // 获得标签集
		for (String label : labelSet) {
			double tempValue = Math.log(parameters.get(label) / Nd);// 先验概率
			/**
			 * 先验概率P(c)= 类c下单词总数/整个训练样本的单词总数 parameters .get(label):类别c对应的文档在训练数据集中的计数
			 * Nd:整个训练样本的单词总数
			 */
			for (String word : words) {
				String lf = label + "_" + word;
				// 计算最大似然概率
				if (allFeatures.containsKey(lf)) {
					tempValue += Math.log((double) (allFeatures.get(lf) + 1) / (labelFeatures.get(label) + V.size()));
					/**
					 * 多项式原理 类条件概率P(tk|c)=(类c下单词tk在各个文档中出现过的次数之和+1)/(类c下单词总数+|V|)
					 * allFeatures.get(lf):类别c与词语 w共同出现的次数 labelFeatures.get(label) +
					 * V.size():类别c下属性总数+该训练文本中词语总数 Laplace Smoothing处理未出现在训练集中的数据 +1
					 */
				} else {
					tempValue += Math.log((double) (1 / (labelFeatures.get(label) + V.size())));
				}
			}
			if (tempValue > maxValue) {
				maxValue = tempValue;
				predLabel = label;
			}
		}
		return predLabel;
	}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!