Java实现基于朴素贝叶斯的情感词分析

在训练阶段,主要完成词频的统计工作。读取训练集,统计出每个词属于该分类下出现的次数,用于后续求解每个词出现在各个类别下的概率,即词汇与主观分类情感之间的关系:

private static void train(){
Map<String,Integer> parameters = new HashMap<>();
try(BufferedReader br = new BufferedReader(new FileReader(trainingData))){ //训练集数据
String sentence;
while(null!=(sentence=br.readLine())){
String[] content = sentence.split("\t| “); //以tab或空格分词
parameters.put(content[0],parameters.getOrDefault(content[0],0)+1);
for (int i = 1; i < content.length; i++) {
parameters.put(content[0]+”-"+content[i], parameters.getOrDefault(content[0]+"-"+content[i], 0)+1);
}
}
}catch (IOException e){
e.printStackTrace();
}
saveModel(parameters);
}
将训练好的模型保存到文件中,可以方便在下次使用时不用重复进行模型的训练:

private static void saveModel(Map<String,Integer> parameters){
try(BufferedWriter bw =new BufferedWriter(new FileWriter(modelFilePath))){
parameters.keySet().stream().forEach(key->{
try {
bw.append(key+"\t"+parameters.get(key)+"\r\n");
} catch (IOException e) {
e.printStackTrace();
}
});
bw.flush();
}catch (IOException e){
e.printStackTrace();
}
}
查看保存好的模型,数据的格式如下:

好评-免费送 3
差评-真烦 1
好评-礼品 3
差评-脏乱差 6
好评-解决 15
差评-挨宰 1
……
这里对训练的模型进行保存,所以如果后续有同样的分类任务时,可以直接在训练集的基础上进行计算,对于分类速度要求较高的任务,能够有效的提高计算的速度。

3、加载模型
加载训练好的模型:

private static HashMap<String, Integer> parameters = null; //用于存放模型
private static Map<String, Double> catagory=null;
private static String[] labels = {“好评”, “差评”, “总数”,“priorGood”,“priorBad”};

private static void loadModel() throws IOException {
parameters = new HashMap<>();
List parameterData = Files.readAllLines(Paths.get(modelFilePath));
parameterData.stream().forEach(parameter -> {
String[] split = parameter.split("\t");
String key = split[0];
int value = Integer.parseInt(split[1]);
parameters.put(key, value);
});

calculateCatagory(); //分类

}
对词进行分类,统计出好评及差评的词频总数,并基于它们先计算得出先验概率:

//计算模型中类别的总数
public static void calculateCatagory() {
catagory = new HashMap<>();
double good = 0.0; //好评词频总数
double bad = 0.0; //差评的词频总数
double total; //总词频

for (String key : parameters.keySet()) {
    Integer value = parameters.get(key);
    if (key.contains("好评-")) {
        good += value;
    } else if (key.contains("差评-")) {
        bad += value;
    }
}
total = good + bad;
catagory.put(labels[0], good);
catagory.put(labels[1], bad);
catagory.put(labels[2], total);
catagory.put(labels[3],good/total); //好评先验概率
catagory.put(labels[4],bad/total);	//差评先验概率

}
查看执行完后的统计值:

“好评”对应的词汇出现的总次数是46316个,“差评”对应的词汇出现的总次数是77292个,训练集词频总数为123608个,并可基于它们计算出它们的先验概率:

该文档属于某个类别的条件概率= 该类别的所有词条词频总数 / 所有词条的词频总数
4、测试阶段
测试阶段,加载我们提前准备好的测试集,对每一行分词后的评论语句进行主观情感的预测:

private static void predictAll() {
double accuracyCount = 0.;//准确个数
int amount = 0; //测试集数据总量

try (BufferedWriter bw = new BufferedWriter(new FileWriter(outputFilePath))) {
    List<String> testData = Files.readAllLines(Paths.get(testFilePath));    //测试集数据
    for (String instance : testData) {
        String conclusion = instance.substring(0, instance.indexOf("\t"));  //已经打好的标签
        String sentence = instance.substring(instance.indexOf("\t") + 1);
        String prediction = predict(sentence);  //预测结果

        bw.append(conclusion + " : " + prediction + "\r\n");
        if (conclusion.equals(prediction)) {
            accuracyCount += 1.;
        }
        amount += 1;
    }
    //计算准确率
    System.out.println("accuracyCount: " + accuracyCount / amount);
} catch (Exception e) {
    e.printStackTrace();
}

}
在测试中,调用下面的predict方法进行分类判断。在计算前,再来回顾一下上面的公式,在程序中进行简化运算:

对于同一个预测样本,分母相同,所以我们可以只比较分子的大小。对分子部分进行进一步简化,对于连乘预算,我们可以对其进行对数操作,变成各部分相加:

这样对于概率的大小比较,就可以简化为比较 先验概率和各个似然概率分别取对数后相加的和。先验概率我们在之前的步骤中已经计算完成并保存,所以这里只计算各词汇在分类条件下的似然概率即可。predict方法的实现如下:

private static String predict(String sentence) {
String[] features = sentence.split(" ");
String prediction;

//分别预测好评和差评
double good = likelihoodSum(labels[0], features) + Math.log(catagory.get(labels[3]));
double bad = likelihoodSum(labels[1], features) + Math.log(catagory.get(labels[4]));
return good >= bad?labels[0]:labels[1];

}
在其中调用likelihood方法计算似然概率的对数和:

//似然概率的计算
public static double likelihoodSum(String label, String[] features) {
double p = 0.0;
Double total = catagory.get(label) + 1;//分母平滑处理
for (String word : features) {
Integer count = parameters.getOrDefault(label + “-” + word, 0) + 1;//分子平滑处理
//计算在该类别的情况下是该词的概率,用该词的词频除以类别的总词频
p += Math.log(count / total);
}
return p;
}
在计算似然概率的方法中,如果出现在训练集中没有包括的词汇,那么会出现它的似然概率为0的情况,为了防止这种情况,对分子分母进行了分别加一的平滑操作。

最后在主函数中调用上面的步骤,最终如果计算出基于样本的好评概率大于等于差评概率,那么将它分类划入“好评”,反之划入“差评”类别,到此就完成了训练和测试的全过程:

public static void main(String[] args) throws IOException {
train();
loadModel();
predictAll();
}
USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值