(4.2)基于LingPipe的文本基本极性分析【demo】
酒店评论情感分析系统(四)——
基于LingPipe的文本基本极性分析【demo】
(Positive (favorable) vs. Negative (unfavorable))
这篇文章为LingPipe官方网站对于Sentiment Ananlysis的学习所给出学习材料;
http://alias-i.com/lingpipe/demos/tutorial/sentiment/read-me.html
官方网站中的学习材料是通过使用逻辑回归分类器基于一定的语言模型对电影评论赋予一定的情感,其中包括两种常见的情感分类问题:
a) 主观性和客观性情感分析
b) 积极性和消极性情感分析
但是此处,我只学习了积极性和消极性情感分析。
下载语料库
此处使用Lilian Lee 和Bo Pang提供的已经完成了极性标注的电影评论语料库Movie Review Data的polarity dataset v2.0,其中包含1000个正面的文本和1000个负面文本,全英文的。如果语料库是中文版的话,则需要下载LingPipe中的Chinese Word Segmentation模块。
基本极性分析
我们以一个简单的分类练习作为开始,即基于布尔极性数据来训练和测试基本分类器,并使产生的分类器能够判断电影评论实质上是积极的或是消极的。
官方网站上的demo是通过命令行的形式读入语料库所在的目录位置,然后基于训练集训练出一个分类器,再基于测试集评估此分类器的正确性。此处我将其变更为以文件的形式读取语料库所在的位置。
1. 前提条件:
1) 在Eclipse中新建一个名为SentimentAnalysis工程,配置LingPipe开源包
2) 在SentimentAnalysis工程下创建一个目录POLARITY_DIR,里面放置语料库polarity dataset v2.0的解压缩文件txt_sentoken。
2. 极性分析代码
新建一个类名为PolarityBasic。
① Main函数
1 public static void main(String[] args) {
2 try {
3 new PolarityBasic().run();
4 } catch (Throwable t) {
5 System.out.println("Thrown: " + t);
6 t.printStackTrace(System.out);
7 }
8 }
② 元参数和构造函数
1 File mPolarityDir;
2 String[] mCategories;
3 DynamicLMClassifier<NGramProcessLM> mClassifier;
4
5 PolarityBasic() {
6 System.out.println("\nBASIC POLARITY DEMO");
7 mPolarityDir = new File("POLARITY_DIR/txt_sentoken"); //获取POLARITY_DIR/txt_sentoken中的语料集
8 mCategories = mPolarityDir.list(); //获取类别neg,pos
9 int nGram = 8;
10 mClassifier = DynamicLMClassifier.createNGramProcess(mCategories,nGram); //使用N-Gram分类方法
11 }
基本极性分析中分类器的构造直接使用的是LingPipe的DynamicLMClassifier。
③ 训练
1 //仅仅先调用训练函数,再调用评估函数
2 void run() throws ClassNotFoundException, IOException {
3 train();
4 evaluate();
5 }
6
7 //我们需要一份测试集和一个训练集,但是我们只有一个语料库,只有人为分割
8 //如果文件名的第2位为9就是训练集
9 boolean isTrainingFile(File file) { //是否是训练集
10 return file.getName().charAt(2) != '9'; // test on fold 9
11 }
12
13 //分类器训练
14 void train() throws IOException {
15 int numTrainingCases = 0; //训练文本数
16 int numTrainingChars = 0; //训练字符数
17 System.out.println("\nTraining.");
18 for (int i = 0; i < mCategories.length; ++i) {
19 String category = mCategories[i];
20 Classification classification = new Classification(category);
21 File file = new File(mPolarityDir,mCategories[i]);
22 File[] trainFiles = file.listFiles();
23 for (int j = 0; j < trainFiles.length; ++j) {
24 File trainFile = trainFiles[j];
25 if (isTrainingFile(trainFile)) { //判断一下是为了让一部分数据作为训练集、一部分作为测试集
26 ++numTrainingCases;
27 String review = Files.readFromFile(trainFile,"ISO-8859-1"); //文本类容
28 numTrainingChars += review.length();
29 Classified<CharSequence> classified =
30 new Classified<CharSequence>(review,classification); //指定内容和类别
31 mClassifier.handle(classified); //训练
32 }
33 }
34 }
35 System.out.println(" # Training Cases=" + numTrainingCases); //训练集文件数
36 System.out.println(" # Training Chars=" + numTrainingChars); //训练集字符总和
37 }
④ 评估
1 //评估
2 void evaluate() throws IOException {
3 System.out.println("\nEvaluating.");
4 int numTests = 0;
5 int numCorrect = 0;
6 for (int i = 0; i < mCategories.length; ++i) {
7 String category = mCategories[i];
8 File file = new File(mPolarityDir,mCategories[i]);
9 File[] trainFiles = file.listFiles();
10 for (int j = 0; j < trainFiles.length; ++j) {
11 File trainFile = trainFiles[j];
12 if (!isTrainingFile(trainFile)) { //测试集
13 String review = Files.readFromFile(trainFile,"ISO-8859-1");
14 ++numTests;
15 Classification classification = mClassifier.classify(review); //对测试集文本进行分类
16 if (classification.bestCategory().equals(category)){ //分类器决策文本所属类=文本原标注所属类,即正确
17 ++numCorrect;
18 }
19 }
20 }
21 }
22 System.out.println(" # Test Cases=" + numTests); //测试文件数
23 System.out.println(" # Correct=" + numCorrect); //正确数
24 System.out.println(" % Correct=" + ((double)numCorrect)/(double)numTests); //正确率
25 }
⑤ 运行结果
BASIC POLARITY DEMO
Training.
# Training Cases=1800
# Training Chars=6989652
Evaluating.
# Test Cases=200
# Correct=163
% Correct=0.815