完全基于情感词典的⽂本情感分析
⽬前情感分析在中⽂⾃然语⾔处理中⽐较⽕热,很多场景下,我们都需要⽤到情感分析。⽐如,做⾦融产品量化交易,需要根据爬取的舆论数据来分析政策和舆论对股市或者基⾦期货的态度;电商交易,根据买家的评论数据,来分析商品的预售率等等。
下⾯我们通过以下⼏点来介绍中⽂⾃然语⾔处理情感分析:
1. 中⽂情感分析⽅法简介;
2. SnowNLP 快速进⾏评论数据情感分析;
3. 基于标注好的情感词典来计算情感值;
4. pytreebank 绘制情感树;
5. 股吧数据情感分类。
中⽂情感分析⽅法简介
情感倾向可认为是主体对某⼀客体主观存在的内⼼喜恶,内在评价的⼀种倾向。它由两个⽅⾯来衡量:⼀
个情感倾向⽅向,⼀个是情感倾向度。
⽬前,情感倾向分析的⽅法主要分为两类:⼀种是基于情感词典的⽅法;⼀种是基于机器学习的⽅法,如基于⼤规模语料库的机器学习。前者需要⽤到标注好的情感词典;后者则需要⼤量的⼈⼯标注的语料作为训练集,通过提取⽂本特征,构建分类器来实现情感的分类。
⽂本情感分析的分析粒度可以是词语、句⼦、段落或篇章。
段落篇章级情感分析主要是针对某个主题或事件进⾏情感倾向判断,⼀般需要构建对应事件的情感词典,如电影评论的分析,需要构建电影⾏业⾃⼰的情感词典,这样效果会⽐通⽤情感词典更好;也可以通过⼈⼯标注⼤量电影评论来构建分类器。句⼦级的情感分析⼤多通过计算句⼦⾥包含的所有情感词的值来得到。
篇章级的情感分析,也可以通过聚合篇章中所有的句⼦的情感倾向来计算得出。因此,针对句⼦级的情感倾向分析,既能解决短⽂本的情感分析,同时也是篇章级⽂本情感分析的基础。
中⽂情感分析的⼀些难点,⽐如句⼦是由词语根据⼀定的语⾔规则构成的,应该把句⼦中词语的依存关系纳⼊到句⼦情感的计算过程中去,不同的依存关系,进⾏情感倾向计算是不⼀样的。⽂档的情感,根据句⼦对⽂档的重要程度赋予不同权重,调整其对⽂档情感的贡献程度等。
SnowNLP 快速进⾏评论数据情感分析
如果有⼈问,有没有⽐较快速简单的⽅法能判断⼀句话的情感倾向,那么 SnowNLP 库就是答案。
SnowNLP 主要可以进⾏中⽂分词、词性标注、情感分析、⽂本分类、转换拼⾳、繁体转简体、提取⽂本关键词、提取摘要、分割句⼦、⽂本相似等。
需要注意的是,⽤ SnowNLP 进⾏情感分析,官⽹指出进⾏电商评论的准确率较⾼,其实是因为它的语料库主要是电商评论数据,但是可以⾃⼰构建相关领域语料库,替换单⼀的电商评论语料,准确率也挺不错的。
1. SnowNLP 安装。
(1)使⽤ pip 安装:
pip install snownlp==0.11.1
(2)使⽤ Github 源码安装。
⾸先,下载 SnowNLP 的源码并解压,在解压⽬录,通过下⾯命令安装:
python  setup.py install
以上⽅式,⼆选⼀安装完成之后,就可以引⼊ SnowNLP 库使⽤了。
from snownlp import SnowNLP
2. 评论语料获取情感值。
⾸先,SnowNLP 对情感的测试值为0到1,值越⼤,说明情感倾向越积极。下⾯我们通过 SnowNLP 测试在京东上的好评、中评、差评的结果。
⾸先,引⼊ SnowNLP 库:
from snownlp import SnowNLP
(1)测试⼀条京东的好评数据:
SnowNLP(u'本本已收到,体验还是很好,功能⽅⾯我不了解,只看外观还是很不错很薄,很轻,也有质感。').sentiments
得到的情感值很⾼,说明买家对商品⽐较认可,情感值为:
0.999950702449061
(2)测试⼀条京东的中评数据:
SnowNLP(u'屏幕分辨率⼀般,送了个极丑的⿏标。').sentiments
得到的情感值⼀般,说明买家对商品看法⼀般,甚⾄不喜欢,情感值为:
0.03251402883400323
(3)测试⼀条京东的差评数据:
SnowNLP(u'很差的⼀次购物体验,细节做得极差了,还有发热有点严重啊,散热不⾏,⽤起来就是烫得厉害,很垃圾!!!').sentiments
得到的情感值⼀般,说明买家对商品不认可,存在退货嫌疑,情感值为:
0.0036849517156107847
以上就完成了简单快速的情感值计算,对评论数据是不是很好⽤呀!!!
使⽤ SnowNLP 来计算情感值,官⽅推荐的是电商评论数据计算准确度⽐较⾼,难道⾮评论数据就不能使⽤ SnowNLP 来计算情感值了吗?当然不是,虽然 SnowNLP 默认提供的模型是⽤评论数据训练的,但是它还⽀持我们根据现有数据训练⾃⼰的模型。
⾸先我们来看看⾃定义训练模型的源码 Sentiment 类,代码定义如下:
class Sentiment(object):
def__init__(self):
self.classifier = Bayes()
def save(self, fname, iszip=True):
self.classifier.save(fname, iszip)
def load(self, fname=data_path, iszip=True):
numpy库需要安装吗self.classifier.load(fname, iszip)
def handle(self, doc):
words = seg.seg(doc)
words = normal.filter_stop(words)
return words
def train(self, neg_docs, pos_docs):
data = []
for sent in neg_docs:
data.append([self.handle(sent), 'neg'])
for sent in pos_docs:
data.append([self.handle(sent), 'pos'])
ain(data)
def classify(self, sent):
ret, prob = self.classifier.classify(self.handle(sent))
if ret == 'pos':
return prob
return 1-prob
通过源代码,我们可以看到,可以使⽤ train⽅法训练数据,并使⽤ save ⽅法和 load ⽅法保存与加载模型。下⾯训练⾃⼰的模型,训练集 和 分别表⽰积极和消极情感语句,两个 TXT ⽂本中每⾏表⽰⼀句语料。
下⾯代码进⾏⾃定义模型训练和保存:
from snownlp import sentiment
sentiment.save('sentiment.marshal')
基于标注好的情感词典来计算情感值
这⾥我们使⽤⼀个⾏业标准的情感词典——玻森情感词典,来⾃定义计算⼀句话、或者⼀段⽂字的情感值。整个过程如下:
1. 加载玻森情感词典;
2. jieba 分词;
3. 获取句⼦得分。
⾸先引⼊包:
import pandas as pd
import jieba
接下来加载情感词典:
df = pd.read_table("bosonnlp//BosonNLP_",sep= "",names=['key','score'])
查看⼀下情感词典前5⾏:
将词 key 和对应得分 score 转成2个 list 列表,⽬的是到词 key 的时候,能对应获取到 score 值:
key = df['key'].list()
score = df['score'].list()
定义分词和统计得分函数:
def getscore(line):
segs = jieba.lcut(line)  #分词
score_list  = [score[key.index(x)] for x in segs if(x in key)]
return  sum(score_list)  #计算得分
最后来进⾏结果测试:
line = "今天天⽓很好,我很开⼼"
print(round(getscore(line),2))
line = "今天下⾬,⼼情也受到影响。"
print(round(getscore(line),2))
获得的情感得分保留2位⼩数:
5.26
-0.96
pytreebank 绘制情感树
1. 安装 pytreebank。
在 Github 上下载,解压之后,进⼊解压⽬录命令⾏,执⾏命令:
python setup.py install
最后通过引⼊命令,判断是否安装成功:
import pytreebank
提⽰,如果在 Windows 下安装之后,报错误:
UnicodeDecodeError: 'gbk' codec can't decode byte 0x92 in position 24783: illegal multibyte sequence
这是由于编码问题引起的,可以在安装⽬录下报错的⽂件中报错的代码地⽅加个encoding='utf-8'编码:
import_tag( "script", contents=format_replacements(open(scriptname,encoding='utf-8').read(), replacements), type="text/javascript" )
2. 绘制情感树。
⾸先引⼊ pytreebank 包:
import pytreebank
然后,加载⽤来可视化的 JavaScript 和 CSS 脚本:
pytreebank.LabeledTree.inject_visualization_javascript()
绘制情感树,把句⼦⾸先进⾏组合再绘制图形:
line = '(4 (0 你) (3 (2 是) (3 (3 (3 谁) (2 的)) (2 谁))))'
得到的情感树如下:
股吧数据情感分类
历经89天的煎熬之后,7⽉15⽇中兴终于盼来了解禁,在此⾸先恭喜中兴,解禁了,希望再踏征程。
但在7⽉15⽇之前,随着中美贸易战不断升级,中兴股价⼜上演了⼀场“跌跌不休”的惨状,我以中美贸易
战背景下中兴通讯在股吧解禁前⼀段时间的评论数据,来进⾏情感数据⼈⼯打标签和分类。其中,把消极、中性、积极分别⽤0、1、2来表⽰。
整个⽂本分类流程主要包括以下6个步骤:
中⽂语料;
分词;
复杂规则;
特征向量;
算法建模;
情感分析。
本次分类算法采⽤ CNN,⾸先引⼊需要的包:
import pandas as pd
import numpy as np
import jieba
import random
import keras
from keras.preprocessing import sequence
dels import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.layers import Embedding
from keras.layers import Conv1D, GlobalMaxPooling1D
from keras.datasets import imdb
dels import model_from_json
from keras.utils import np_utils
import matplotlib.pyplot as plt
继续引⼊停⽤词和语料⽂件:
dir = "D://ProgramData//PythonWorkSpace//chat//chat8//"
ad_csv(dir +"",index_col=False,quoting=3,sep="\t",names=['stopword'], encoding='utf-8') stopwords=stopwords['stopword'].values
df_data1 = pd.read_csv(dir+"data1.csv",encoding='utf-8')
df_data1.head()
下图展⽰数据的前5⾏:
接着进⾏数据预处理,把消极、中性、积极分别为0、1、2的预料分别拿出来:
#把内容有缺失值的删除
df_data1.dropna(inplace=True)
#抽取⽂本数据和标签
data_1 = df_data1.loc[:,['content','label']]
#把消极中性积极分别为0、1、2的预料分别拿出来
data_label_0 = data_1.loc[data_1['label'] ==0,:]
data_label_1 = data_1.loc[data_1['label'] ==1,:]
data_label_2 = data_1.loc[data_1['label'] ==2,:]
接下来,定义中⽂分词函数:
#定义分词函数
def preprocess_text(content_lines, sentences, category):
for line in content_lines:
try:
segs=jieba.lcut(line)
segs = filter(lambda x:len(x)>1, segs)
segs = [v for v in segs if not str(v).isdigit()]#去数字
segs = list(filter(lambda x:x.strip(), segs)) #去左右空格
segs = filter(lambda x:x not in stopwords, segs)
temp = "".join(segs)
if(len(temp)>1):
sentences.append((temp, category))
except Exception:
print(line)
continue
⽣成训练的分词数据,并进⾏打散,使其分布均匀:
#获取数据
data_label_0_content = data_label_0['content'].list()
data_label_1_content = data_label_1['content'].list()
data_label_2_content = data_label_2['content'].list()
#⽣成训练数据
sentences = []
preprocess_text(data_label_0_content, sentences, 0)
preprocess_text(data_label_1_content, sentences, 1)
preprocess_text(data_label_2_content, sentences,2)
#我们打乱⼀下顺序,⽣成更可靠的训练集
random.shuffle(sentences)
对数据集进⾏切分,按照训练集合测试集7:3的⽐例:
#所以把原数据集分成训练集的测试集,咱们⽤sklearn⾃带的分割函数。
del_selection import train_test_split