基于情感词典的情感分析应该是最简单传统的情感分析方法。
本文中使用情感词典进行情感分析的思路为:
- 对文档分词,找出文档中的情感词、否定词以及程度副词
- 然后判断每个情感词之前是否有否定词及程度副词,将它之前的否定词和程度副词划分为一个组
- 如果有否定词将情感词的情感权值乘以-1,如果有程度副词就乘以程度副词的程度值
- 最后所有组的得分加起来,大于0的归于正向,小于0的归于负向。(得分的绝对值大小反映了积极或消极的程度)
主要参考文章:
目录
1.准备数据
1.1 BosonNLP情感词典
1.2 否定词词典
1.3 程度副词词典
1.4 停用词词典
2. 数据预处理
2.1 使用jieba分词并去除停用词
3.分数计算
3.1 找出文本中的情感词,否定词和程度副词
3.2 计算情感词的分数
4.完整代码
1.1 BosonNLP情感词典
https://kexue.fm/usr/uploads/2017/09/1922797046.zip
从下载的文件里,随便粘了几个正向的情感词,词后面的数字表示的是情感词的情感分值,一般正向的都是正数,负向的是负数:
注:由于BosonNLP是基于微博、新闻、论坛等数据来源构建的情感词典,因此拿来对其他类别的文本进行分析效果可能不好
也有一种将所有情感词的情感分值设为1的方法来计算,想要详细了解可参考此文章:文本情感分类(一):传统模型
1.2 否定词词典
文本情感分类(一):传统模型中提供了一个情感极性词典的下载包,包中带了一个否定词的txt。
https://kexue.fm/usr/uploads/2017/09/1922797046.zip
1.3 程度副词词典
从程度级别词语.txt中选取了一部分程度副词,可以看到只有程度词,没有程度值。
这里做了一个简单的程度副词标记,大于1,表示情感加强,小于1,表示情感弱化,下面主要按照极其1.8,超1.6,很1.5,较1,稍0.7,欠0.5进行了一个简单的标记,如下所示。也可以根据自己的需求及及进行修改。
1.4 停用词词典
参考的是https://github.com/isnowfy/snownlp/blob/master/snownlp/normal/stopwords.txt(为什么高兴成停用词了?_?)
要注意一下需要将否定词或者是程度副词的词典过滤掉,不然否定词在去除停用词的时候都过滤掉了,就缺少了一些程度副词或者否定词。使用以下方法进行过滤:
(代码复制过来缩进怎么成这样,强迫症看着难受。。。)
2.1 使用jieba分词并去除停用词
3.1 找出文本中的情感词,否定词和程度副词
如句子:我今天很高兴也非常开心,去除停用词后得到:
['很', '高兴', '非常', '开心']
情感词:高兴、开心,key为单词的索引,value为情感权值:
sen_word:{1: '1.48950851679', 3: '2.61234173173'}
否定词:没有出现否定词,所以否定词为空:
not_word:{}程度副词:很、非常
degree_word:{0: '1.5', 2: '1.8'}
3.2 计算情感词的分数
采用的规则如下:
遍历所有的情感词,查看当前情感词的前面是否有否定词和程度副词,如果没有否定词,就对当前情感词乘以1,如果有否定词或者有多个否定词,可以乘以(-1)^否定词的个数;如果有程度副词,就在当前情感词前面乘以程度副词的程度等级。
伪代码:
finalSentiScore = (-1) ^ (num of notWords) * degreeNum * sentiScore#计算情感词的分数 def score_sentiment(sen_word,not_word,degree_word,seg_result): #权重初始化为1 W = 1 score = 0 #情感词下标初始化 sentiment_index = -1 #情感词的位置下标集合 sentiment_index_list = list(sen_word.keys()) #遍历分词结果 for i in range(0,len(seg_result)): #如果是情感词 if i in sen_word.keys(): #权重*情感词得分 score += W*float(sen_word[i]) #情感词下标加一,获取下一个情感词的位置 sentiment_index += 1 if sentiment_index < len(sentiment_index_list)-1: #判断当前的情感词与下一个情感词之间是否有程度副词或否定词 for j in range(sentiment_index_list[sentiment_index],sentiment_index_list[sentiment_index+1]): #更新权重,如果有否定词,权重取反 if j in not_word.keys(): W *= -1 elif j in degree_word.keys(): W *= float(degree_word[j]) #定位到下一个情感词 if sentiment_index < len(sentiment_index_list)-1: i = sentiment_index_list[sentiment_index+1] return score
‘我今天很高兴也非常开心’分词去停用词得到:['很', '高兴', '非常', '开心']
最开始W=1,score=0
第一个情感词是高兴,高兴的情感权值为1.48950851679,score=W*情感权值=1.48950851679
高兴和下一个情感词开心之间出现了非常,程度值为1.8,因此W=W*1.8=1.8
然后获取下一个情感词
下一个情感词是开心,此时W=1.8,score=score+1.8*2.61234173173= 6.191723633904
遍历结束
问题:这样写漏掉了第一个情感词前的否定词和程度副词。。。(这里漏掉了“很”)
实验结果:
随机测试了5个句子,可以看出整体上情感分析的结果不错,越积极的文本评分越高,消极文本同理。