中文情感词汇本体库_数据语言

2022-10-02 15:28:49 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

基于情感词典的情感分析应该是最简单传统的情感分析方法。

本文中使用情感词典进行情感分析的思路为:

  1. 对文档分词,找出文档中的情感词、否定词以及程度副词
  2. 然后判断每个情感词之前是否有否定词及程度副词,将它之前的否定词和程度副词划分为一个组
  3. 如果有否定词将情感词的情感权值乘以-1,如果有程度副词就乘以程度副词的程度值
  4. 最后所有组的得分加起来,大于0的归于正向,小于0的归于负向。(得分的绝对值大小反映了积极或消极的程度)

主要参考文章:

https://blog.csdn.net/lom9357bye/article/details/79058946

https://blog.csdn.net/qq_36489878/article/details/103772714

目录

1.准备数据

1.1 BosonNLP情感词典

1.2 否定词词典

1.3 程度副词词典

1.4 停用词词典

2. 数据预处理

2.1 使用jieba分词并去除停用词

3.分数计算

3.1 找出文本中的情感词,否定词和程度副词

3.2 计算情感词的分数

4.完整代码


1.准备数据

1.1 BosonNLP情感词典

https://kexue.fm/usr/uploads/2017/09/1922797046.zip

从下载的文件里,随便粘了几个正向的情感词,词后面的数字表示的是情感词的情感分值,一般正向的都是正数,负向的是负数:

代码语言:javascript复制
居家 2.08857470795
畅想 2.08875837264
2AM 2.08890952167
萌萌 2.08890952167
霍思燕 2.08890952167
阳光 2.08902889821
知足 2.08909186445

注:由于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进行了一个简单的标记,如下所示。也可以根据自己的需求及及进行修改。

代码语言:javascript复制
百分之百,1.8
倍加,1.8
备至,1.8
不得了,1.8
不堪,1.8
不可开交,1.8
不亦乐乎,1.8
不折不扣,1.8
彻头彻尾,1.8
充分,1.8
到头,1.8
地地道道,1.8
非常,1.8
极,1.8
极度,1.8
极端,1.8
极其,1.8
极为,1.8
截然,1.8
尽,1.8
惊人地,1.8
绝,1.8
绝顶,1.8
绝对,1.8
绝对化,1.8
刻骨,1.8
酷,1.8
满,1.8
满贯,1.8
满心,1.8
莫大,1.8
奇,1.8
入骨,1.8
甚为,1.8
十二分,1.8
十分,1.8
十足,1.8
死,1.8
滔天,1.8
痛,1.8
透,1.8
完全,1.8
完完全全,1.8
万,1.8
万般,1.8
万分,1.8
万万,1.8
无比,1.8
无度,1.8
无可估量,1.8
无以复加,1.8
无以伦比,1.8
要命,1.8
要死,1.8
已极,1.8
已甚,1.8
异常,1.8
逾常,1.8
贼,1.8
之极,1.8
之至,1.8
至极,1.8
卓绝,1.8
最为,1.8
佼佼,1.8
郅,1.8
綦,1.8
齁,1.8
最,1.8
不过,1.5
不少,1.5
不胜,1.5
惨,1.5
沉,1.5
沉沉,1.5
出奇,1.5
大为,1.5
多,1.5
多多,1.5
多加,1.5
多么,1.5
分外,1.5
格外,1.5
够瞧的,1.5
够戗,1.5
好,1.5
好不,1.5
何等,1.5
很,1.5
很是,1.5
坏,1.5
可,1.5
老,1.5
老大,1.5
良,1.5
颇,1.5
颇为,1.5
甚,1.5
实在,1.5
太,1.5
太甚,1.5
特,1.5
特别,1.5
尤,1.5
尤其,1.5
尤为,1.5
尤以,1.5
远,1.5
着实,1.5
曷,1.5
碜,1.5
大不了,0.8
多,0.8
更,0.8
更加,0.8
更进一步,0.8
更为,0.8
还,0.8
还要,0.8
较,0.8
较比,0.8
较为,0.8
进一步,0.8
那般,0.8
那么,0.8
那样,0.8
强,0.8
如斯,0.8
益,0.8
益发,0.8
尤甚,0.8
逾,0.8
愈,0.8
愈 ... 愈,0.8
愈发,0.8
愈加,0.8
愈来愈,0.8
愈益,0.8
远远,0.8
越 ... 越,0.8
越发,0.8
越加,0.8
越来越,0.8
越是,0.8
这般,0.8
这样,0.8
足,0.8
足足,0.8
点点滴滴,0.7
多多少少,0.7
怪,0.7
好生,0.7
还,0.7
或多或少,0.7
略,0.7
略加,0.7
略略,0.7
略微,0.7
略为,0.7
蛮,0.7
稍,0.7
稍稍,0.7
稍微,0.7
稍为,0.7
稍许,0.7
挺,0.7
未免,0.7
相当,0.7
些,0.7
些微,0.7
些小,0.7
一点,0.7
一点儿,0.7
一些,0.7
有点,0.7
有点儿,0.7
有些,0.7
半点,0.5
不大,0.5
不丁点儿,0.5
不甚,0.5
不怎么,0.5
聊,0.5
没怎么,0.5
轻度,0.5
弱,0.5
丝毫,0.5
微,0.5
相对,0.5
不为过,1.6
超,1.6
超额,1.6
超外差,1.6
超微结构,1.6
超物质,1.6
出头,1.6
多,1.6
浮,1.6
过,1.6
过度,1.6
过分,1.6
过火,1.6
过劲,1.6
过了头,1.6
过猛,1.6
过热,1.6
过甚,1.6
过头,1.6
过于,1.6
过逾,1.6
何止,1.6
何啻,1.6
开外,1.6
苦,1.6
老,1.6
偏,1.6
强,1.6
溢,1.6
忒,1.6

1.4 停用词词典

参考的是https://github.com/isnowfy/snownlp/blob/master/snownlp/normal/stopwords.txt(为什么高兴成停用词了?_?)

要注意一下需要将否定词或者是程度副词的词典过滤掉,不然否定词在去除停用词的时候都过滤掉了,就缺少了一些程度副词或者否定词。使用以下方法进行过滤:

(代码复制过来缩进怎么成这样,强迫症看着难受。。。)

代码语言:javascript复制
#生成stopword表,需要去除一些否定词和程度词汇
stopwords = set()
fr = open('停用词.txt','r',encoding='utf-8')
for word in fr:
	stopwords.add(word.strip())#Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
#读取否定词文件
not_word_file = open('否定词.txt','r ',encoding='utf-8')
not_word_list = not_word_file.readlines()
not_word_list = [w.strip() for w in not_word_list]
#读取程度副词文件
degree_file = open('程度副词.txt','r ')
degree_list = degree_file.readlines()
degree_list = [item.split(',')[0] for item in degree_list]
#生成新的停用词表			
with open('stopwords.txt','w',encoding='utf-8') as f:
	for word in stopwords:
		if(word not in not_word_list) and (word not in degree_list):
			f.write(word 'n')

2. 数据预处理

2.1 使用jieba分词并去除停用词

代码语言:javascript复制
#jieba分词后去除停用词
def seg_word(sentence):
	seg_list = jieba.cut(sentence)
	seg_result = []
	for i in seg_list:
		seg_result.append(i)
	stopwords = set()
	with open('stopwords.txt','r') as fr:
		for i in fr:
			stopwords.add(i.strip())
	return list(filter(lambda x :x not in stopwords,seg_result))

3.分数计算

3.1 找出文本中的情感词,否定词和程度副词

如句子:我今天很高兴也非常开心,去除停用词后得到: ['很', '高兴', '非常', '开心'] 情感词:高兴、开心,key为单词的索引,value为情感权值: sen_word:{1: ‘1.48950851679’, 3: ‘2.61234173173’} 否定词:没有出现否定词,所以否定词为空: not_word:{} 程度副词:很、非常 degree_word:{0: ‘1.5’, 2: ‘1.8’}

代码语言:javascript复制
#找出文本中的情感词、否定词和程度副词
def classify_words(word_list):
	#读取情感词典文件
	sen_file = open('BosonNLP_sentiment_score.txt','r ',encoding='utf-8')
	#获取词典文件内容
	sen_list = sen_file.readlines()
	#创建情感字典
	sen_dict = defaultdict()
	#读取词典每一行的内容,将其转换成字典对象,key为情感词,value为其对应的权重
	for i in sen_list:
		if len(i.split(' '))==2:
			sen_dict[i.split(' ')[0]] = i.split(' ')[1]

	#读取否定词文件
	not_word_file = open('否定词.txt','r ',encoding='utf-8')
	not_word_list = not_word_file.readlines()
	#读取程度副词文件
	degree_file = open('程度副词.txt','r ')
	degree_list = degree_file.readlines()
	degree_dict = defaultdict()
	for i in degree_list:
		degree_dict[i.split(',')[0]] = i.split(',')[1]

	sen_word = dict()
	not_word = dict()
	degree_word = dict()
	#分类
	for i in range(len(word_list)):
		word = word_list[i]
		if word in sen_dict.keys() and word not in not_word_list and word not in degree_dict.keys():
			# 找出分词结果中在情感字典中的词
			sen_word[i] = sen_dict[word]
		elif word in not_word_list and word not in degree_dict.keys():
			# 分词结果中在否定词列表中的词
			not_word[i] = -1
		elif word in degree_dict.keys():
			# 分词结果中在程度副词中的词
			degree_word[i]  = degree_dict[word]


	#关闭打开的文件
	sen_file.close()
	not_word_file.close()
	degree_file.close()
	#返回分类结果
	return sen_word,not_word,degree_word

3.2 计算情感词的分数

采用的规则如下:

遍历所有的情感词,查看当前情感词的前面是否有否定词和程度副词,如果没有否定词,就对当前情感词乘以1,如果有否定词或者有多个否定词,可以乘以(-1)^否定词的个数;如果有程度副词,就在当前情感词前面乘以程度副词的程度等级。 伪代码:

代码语言:javascript复制
finalSentiScore = (-1) ^ (num of notWords) * degreeNum * sentiScore

代码语言:javascript复制
#计算情感词的分数
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 遍历结束 问题:这样写漏掉了第一个情感词前的否定词和程度副词。。。(这里漏掉了“很”)

4.完整代码

代码语言:javascript复制
from collections import defaultdict
import os
import re
import jieba
import codecs
#生成stopword表,需要去除一些否定词和程度词汇
stopwords = set()
fr = open('停用词.txt','r',encoding='utf-8')
for word in fr:
stopwords.add(word.strip())#Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
#读取否定词文件
not_word_file = open('否定词.txt','r ',encoding='utf-8')
not_word_list = not_word_file.readlines()
not_word_list = [w.strip() for w in not_word_list]
#读取程度副词文件
degree_file = open('程度副词.txt','r ')
degree_list = degree_file.readlines()
degree_list = [item.split(',')[0] for item in degree_list]
#生成新的停用词表			
with open('stopwords.txt','w',encoding='utf-8') as f:
for word in stopwords:
if(word not in not_word_list) and (word not in degree_list):
f.write(word 'n')
#jieba分词后去除停用词
def seg_word(sentence):
seg_list = jieba.cut(sentence)
seg_result = []
for i in seg_list:
seg_result.append(i)
stopwords = set()
with open('stopwords.txt','r') as fr:
for i in fr:
stopwords.add(i.strip())
return list(filter(lambda x :x not in stopwords,seg_result))		
#找出文本中的情感词、否定词和程度副词
def classify_words(word_list):
#读取情感词典文件
sen_file = open('BosonNLP_sentiment_score.txt','r ',encoding='utf-8')
#获取词典文件内容
sen_list = sen_file.readlines()
#创建情感字典
sen_dict = defaultdict()
#读取词典每一行的内容,将其转换成字典对象,key为情感词,value为其对应的权重
for i in sen_list:
if len(i.split(' '))==2:
sen_dict[i.split(' ')[0]] = i.split(' ')[1]
#读取否定词文件
not_word_file = open('否定词.txt','r ',encoding='utf-8')
not_word_list = not_word_file.readlines()
#读取程度副词文件
degree_file = open('程度副词.txt','r ')
degree_list = degree_file.readlines()
degree_dict = defaultdict()
for i in degree_list:
degree_dict[i.split(',')[0]] = i.split(',')[1]
sen_word = dict()
not_word = dict()
degree_word = dict()
#分类
for i in range(len(word_list)):
word = word_list[i]
if word in sen_dict.keys() and word not in not_word_list and word not in degree_dict.keys():
# 找出分词结果中在情感字典中的词
sen_word[i] = sen_dict[word]
elif word in not_word_list and word not in degree_dict.keys():
# 分词结果中在否定词列表中的词
not_word[i] = -1
elif word in degree_dict.keys():
# 分词结果中在程度副词中的词
degree_word[i]  = degree_dict[word]
#关闭打开的文件
sen_file.close()
not_word_file.close()
degree_file.close()
#返回分类结果
return sen_word,not_word,degree_word
#计算情感词的分数
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
#计算得分
def sentiment_score(sentence):
#1.对文档分词
seg_list = seg_word(sentence)
#2.将分词结果转换成字典,找出情感词、否定词和程度副词
sen_word,not_word,degree_word = classify_words(seg_list)
#3.计算得分
score = score_sentiment(sen_word,not_word,degree_word,seg_list)
return score
print("我今天很高兴也非常开心    ",sentiment_score("我今天很高兴也非常开心"))
print('天灰蒙蒙的,路上有只流浪狗,旁边是破旧不堪的老房子   ',sentiment_score('天灰蒙蒙的,路上有只流浪狗,旁边是破旧不堪的老房子'))
print('愤怒、悲伤和埋怨解决不了问题    ',sentiment_score('愤怒、悲伤和埋怨解决不了问题'))
print('要每天都开心快乐    ',sentiment_score('要每天都开心快乐'))
print('我不喜欢这个世界,我只喜欢你    ',sentiment_score('我不喜欢这个世界,我只喜欢你'))

实验结果:

随机测试了5个句子,可以看出整体上情感分析的结果不错,越积极的文本评分越高,消极文本同理。

当然这种方法受很多因素的影响,不可控性大,比如情感字典的选择(里面情感词的权重赋值)、停用词表的选择、分数计算规则的设计。而基于机器(深度)学习的方法无疑是优于基于情感字典的方法的。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/172413.html原文链接:https://javaforall.cn

0 人点赞