Hadoop课程结课设计时老师让做一个评价预测,完成后将核心的要点记录下来,方便后续同学可以参考
hadoop-word-predict
基于hadoop的评价预测系统
实验的题目如下
编写java程序,使其能够实现基于上传至hdfs的“学号_上传文件.txt”数据集训练情感分类器的目的。在训练的过程中,应过滤包含非中文字符或全部由非中文字符构成的词语。保存模型文件至“学号_模型.txt”文件中。格式要求:
类标_词语1\t计数
类标_词语2\t计数
类标_词语3\t计数
……
类标1\t计数
类标2\t计数
基于训练得到的模型参数(即Nc和Ncw,其中,c表示情感标签类别,c∈{好评,差评},w∈V,V是“学号_上传文件.data”数据集包含的中文词典集合),对“test.txt”数据集中的各条记录进行“情感标签”判别。判别结果输出至“学号_预测结果.txt”文件中。“学号_预测结果.txt”文件中的每行是行号及“test.txt”中预测的“情感标签”:格式要求:
1 情感标签
2 情感标签
3 情感标签
……
2000 情感标签
训练和预测用的数据格式如下
好评 几乎 凌晨 才 到 包头 包头 没有 什么 特别 好 酒店 每次 来 就是 住 这家 所以 没有 忒 多 对比 感觉 行 下次 还是 得到 这里 来 住
好评 住 过 几次 东莞 酒店 海悦 地理位置 早餐 最棒 听说 朋友 说 请来 厨师 来头 呵呵 冲 这个 去
好评 酒店设施 比较 不错 就是 携程 价格 酒店 前台 一样 没有 竞争力
好评 房间 不算 大 中规中矩 北方 服务 真的 不敢恭维 CHECK IN 后 没有 服务生 帮 你 拿 行李 到 房间 去 周围 酒店 没 啥 逛 自己 吃 早饭 可以 去 万豪 喜来登 之间 那条 路 永和 豆浆店 很 便宜
好评 通过 朋友 介绍 住 苏州 南林 饭店 一进 酒店 大堂 感觉 很 好 酒店 行李 员 前台 服务员 大堂 经理 很 热情 有种 宾至如归 感觉 房间 很 特色 背景 墙上 金色 字体 诗词 我 住 朝南 景观 房 感觉 真的 很 好 一 出门 就是 娱乐 酒吧 一条街 美食 一条街 出门 很 方便 下次 来 苏州 我 会 选择 南林 我 会 介绍 我 朋友 入住 南林 饭店
好评 西宁 住 过 几个 酒店 此 酒店 虽然 比起 内地 四星级 差 一些 但 西宁 算是 不错 价格 不 高 房间 里 东西 倒 干净 地毯 有点 脏 用 地 暖 感觉 比 空调 舒服 多 没有 噪音 安全 周围环境 尚可
好评 房间 算 整齐 宽敞 我 住 标准间 大床 房 只是 浴室 淋浴 笼头 不太好 出水 不 均匀 洗澡 不 舒服 服务 不错 到 酒店 早上 点 让 我 提前 入住 而且 结账 速度 比较 快 不 耽误时间 酒店 靠近 号 地铁 算 方便
内容说明
环境配置和文件上传这里就不做赘余的描述了,主要讲解下实现的思想
为了实现预测模型使用了两组mapperreducer
第一组:进行词频统计,得到每个词在对应评价下的数目,格式如下
类标_词语1\t计数
类标_词语2\t计数
类标_词语3\t计数
...
好评_几乎 \t 23
mapper实现:
将一行数据先以\t进行分割得到关键字行,再将关键字行以空格分割,分割后以<评价词_关键字,1>写入上下文,并将词性统计也写入上下文
//把value对应的行数据按照指定的间隔符拆分开
String[] words = value.toString().split("\t");
//word[0]是评价(好评或者差评)
//word[1]是评价的内容
//过滤一下有些评价后面没有关键字
if (words.length == 2){
String[] pjs = words[1].split(" ");
for (String pj : pjs) {
//如果含有非中文的就过滤掉
if (isAllChinese(pj)){
context.write(new Text(words[0] + "_" + pj), new IntWritable(1));
}
}
//统计好评差评数目
context.write(new Text("统计_"+words[0]), new IntWritable(1));
}
为了判断分词结果是否为纯中文,编写了一个方法做检验
/**
* 判断字符串是否全为中文
* @param str
* @return
*/
public boolean isAllChinese(String str) {
if (str == null) {
return false;
}
for (char c : str.toCharArray()) {
if (!isChinese(c)) {
return false;
}
}
return true;
}
/**
* 判断单个字符是否为中文
* @param c
* @return
*/
public Boolean isChinese(char c) {
return c >= 0x4E00 && c <= 0x9Fa5;
}
reducer实现
读取上下文,对第二个属性值进行累加,等到每个组合关键字的计数,再以<评价词_关键字,计数>写入上下文
/**
*
* map端 输出到reduce端,按相同的key分发到同一个reduce去执行
* (hello,<1,1,1>)
* (welcome,<1>)
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values,