酒店评论情感分析系统(三)——
将分词和去停用词后的评论文本基于“环境、卫生、价格、服务”分类
思想:
将进行了中文分词和去停用词之后得到的词或短语按序存在一个数组(iniArray)中,从中找出所有和“环境、卫生、价格、服务”四个方面相关的词或短语,并记录下其位置信息(sortRefNum)。然后按照位置信息,对每一个标记出的关键词,记录下从当前关键词起到下一个关键词止的信息,放入一个String型的数组中(midArray),最后将此数组中的关键词再分别基于“环境、卫生、价格、服务”四个方面分类(fourClass)。
前提条件:
1) 此步骤是在【(3.1)用ictclas4j进行中文分词,并去除停用词】后所得到的文本基础上的实验;
2) 在sentence文件目录中的srcFile目录下,须自己建立以下几个额外的词库:
EnvironmentRef:与环境相关的相关词汇,比如:交通,设施等;
HealthRef:与卫生相关的相关词汇,比如:卫生,脏等;
PriceRef:与价钱相关的相关词汇,比如:收费,价格等;
ServiceRef:与服务相关的相关词汇,比如:服务,态度等
RefWords:以上四个相关词表的总和。
代码实现:
新建一个class(如:Fenlei.java)
1 import java.io.BufferedReader; 2 import java.io.File; 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.IOException; 6 import java.io.InputStreamReader; 7 import java.util.HashSet; 8 import java.util.Set; 9 10 11 public class Fenglei { 12 13 //将分词和去停用词的结果提取出来 14 String destFile = "." + File.separator + "destFile" + File.separator + "酒店评论.txt"; 15 public static final String RefWord = "." + File.separator + "srcFile" + File.separator + "RefWords.txt"; 16 public static final String EnvironmentRef = "." + File.separator + "srcFile" + File.separator + "EnvironmentRef.txt"; 17 public static final String HealthRef = "." + File.separator + "srcFile" + File.separator + "HealthRef.txt"; 18 public static final String PriceRef = "." + File.separator + "srcFile" + File.separator + "PriceRef.txt"; 19 public static final String ServiceRef = "." + File.separator + "srcFile" + File.separator + "ServiceRef.txt"; 20 21 public void fenlei(){ 22 try{ 23 //读取原文件和相关词表 24 BufferedReader srcBr = new BufferedReader(new InputStreamReader(new FileInputStream(new File(destFile)))); 25 BufferedReader refBr = new BufferedReader(new InputStreamReader(new FileInputStream(new File(RefWord)))); 26 BufferedReader environmentRefBr = new BufferedReader(new InputStreamReader(new FileInputStream(new File(EnvironmentRef)))); 27 BufferedReader healthRefBr = new BufferedReader(new InputStreamReader(new FileInputStream(new File(HealthRef)))); 28 BufferedReader priceRefBr = new BufferedReader(new InputStreamReader(new FileInputStream(new File(PriceRef)))); 29 BufferedReader serviceRefBr = new BufferedReader(new InputStreamReader(new FileInputStream(new File(ServiceRef)))); 30 31 //将分词去停用词后的单词,按序放在String数组中 32 String paragraph = null; 33 String[] iniArray = null; 34 for(; (paragraph = srcBr.readLine()) != null;){ 35 iniArray = paragraph.split(" "); 36 } 41 42 Set<String> refWordSet = getSet(refBr); //相关词汇集 43 Set<String> environmentSet = getSet(environmentRefBr); 44 Set<String> healthSet = getSet(healthRefBr); 45 Set<String> priceSet = getSet(priceRefBr); 46 Set<String> serviceSet = getSet(serviceRefBr); 47 48 //用一个int数组refNum存放分析文本中寻找相关关键词 49 int[] refNum = new int[iniArray.length]; 50 int refNumcount = 0; 51 for(int i = 0; i< iniArray.length; i++){ 52 if(refWordSet.contains(iniArray[i])){ 53 refNum[refNumcount++] = i; 54 } 55 } 56 57 //对refNum数组进行排序 58 int[] sortRefNum = new int[refNumcount]; 59 bubble(refNum); 60 for(int i = refNum.length-refNumcount,j=0;j<refNumcount;i++,j++){ 61 sortRefNum[j] = refNum[i]; 62 } 63 64 //对属于同一相关的短语进行记录 65 String[] midArray = new String[refNumcount]; 66 int midArrayCount = 0; 67 for(int i=0; i<refNumcount-1; i++){ 68 int j=sortRefNum[i]; 69 midArray[midArrayCount] = ""; 70 for(;j < sortRefNum[i+1];j++ ){ 71 if(iniArray[j] != null){ 73 midArray[midArrayCount] += iniArray[j].toString()+" "; 74 } 75 } 76 midArrayCount++; 77 } 78 midArray[midArrayCount] = ""; 79 for(int i = sortRefNum[refNumcount-1];i < iniArray.length;i++){ 80 midArray[midArrayCount] += iniArray[i].toString()+" "; 81 } 82 83 //对相关短语属于同一大类的短语进行合并整理,如“光线”类和“隔音”应该同属于“环境”类 84 String[] fourClass = new String[4]; 85 fourClass[0] = "环境: "; 86 fourClass[1] = "卫生: "; 87 fourClass[2] = "价格: "; 88 fourClass[3] = "服务: "; 89 for(int j=0;j<=midArrayCount;j++){ 90 if(environmentSet.contains(iniArray[sortRefNum[j]])){ //0-环境 91 fourClass[0] += midArray[j].toString()+" "; 92 }else{ 93 if(healthSet.contains(iniArray[sortRefNum[j]])){ //1-卫生 94 fourClass[1] += midArray[j].toString()+" "; 95 }else{ 96 if(priceSet.contains(iniArray[sortRefNum[j]])){ //2-价格 97 fourClass[2] += midArray[j].toString()+" "; 98 }else{ 99 if(serviceSet.contains(iniArray[sortRefNum[j]])){ //3-服务 100 fourClass[3] += midArray[j].toString()+" "; 101 } 102 } 103 } 104 } 105 } 106 }catch(FileNotFoundException e){ 107 // TODO Auto-generated catch block 108 e.printStackTrace(); 109 } catch(Exception e){ 110 e.printStackTrace(); 111 } 112 } 113 114 //冒泡排序 115 public int[] bubble(int[] array) { 116 int temp = 0; 117 for (int i = array.length - 1; i > 0; --i) { 118 for (int j = 0; j < i; j++) { 119 if (array[j] > array[j+1]) { 120 temp = array[j]; 121 array[j] = array[j+1]; 122 array[j+1] = temp; 123 } 124 } 125 } 126 return array; 127 } 128 129 130 //词汇表的集合 131 public Set<String> getSet(BufferedReader br){ 132 Set<String> wordSet = new HashSet<String>(); //用来放词汇的集合 133 String word = null; 134 try { 135 for(; (word = br.readLine()) != null;){ 136 wordSet.add(word); 137 } 138 } catch (IOException e) { 139 // TODO Auto-generated catch block 140 e.printStackTrace(); 141 } 142 return wordSet; 143 } 144 145 public static void main(String[] args){ 146 new Fenglei().fenlei(); 147 } 149 }
运行效果:
源评论文本:
总体评价:性价比很高,交通便利,周边吃喝玩乐设施齐全,对面就是家乐福。但是前台男客服服务态度很一般,酒店光线太暗看不清,总感觉脏脏的,并且隔音效果一般,有一点点吵,导致晚上睡觉不踏实。对于价钱,三星级价格有点高,一次性用品要收费,觉得很不合理。
分词和去停用词后的文本:
总体 评价 性 价 高 交通 便利 周边 吃喝玩乐 设施 齐全 对面 家乐福 前台 男客 服 服务 态度 一般 酒店 光线 太 暗 不 清 总 感觉 脏脏 隔音 效果 一般 一点点 吵 导致 晚上 睡觉 不 踏实 价钱 三星级 价格 点 高 一次性 用品 收费 觉得 不 合理
midArray数组中的内容:
交通 便利 周边 吃喝玩乐
设施 齐全 对面 家乐福 前台 男客 服
服务
态度 一般 酒店
光线 太 暗 不 清 总 感觉
脏脏
隔音 效果 一般 一点点 吵 导致 晚上 睡觉 不 踏实
价钱 三星级
价格 点 高 一次性 用品
收费 觉得 不 合理
按“环境、卫生、价格、服务”分类后的结果:
环境:交通 便利 周边 吃喝玩乐 设施 齐全 对面 家乐福 前台 男客 服 光线 太 暗 不 清 总 感觉 隔音 效果 一般 一点点 吵 导致 晚上 睡觉 不 踏实
卫生: 脏脏
价格: 价钱 三星级 价格 点 高 一次性 用品 收费 觉得 不 合理
服务: 服务 态度 一般 酒店
缺点:
此实验的分类效果一般,对于源文本的输入格式有一定的限制,比如对于“前台男客服服务态度很一般”这一句,最终的分类结果变为“环境: 前台 男客 服;服务: 服务 态度 一般”。故,此实验只是作为一种思想的体现,如有更好的文本细分的想法,欢迎留言探讨!