sentiment analysis

Sentiment Analysis(情感分析),又称倾向性分析,意见抽取(Opinion extraction),意见挖掘(Opinion mining),情感挖掘(Sentiment mining),主观分析(Subjectivity analysis),它是对带有情感色彩的主观性文本进行分析、处理、归纳和推理的过程,是NLP中一种常见应用。

大致有以下几种应用场景:

商品评价

在上网购物司空见惯的时代,购物评价铺天盖地,淘宝/京东/大众点评/…,客户的评价(好评positive/差评negative)变得对消费者、店家和app平台越来越重要。很多商户需要及时分析自家产品的评价,发现问题进行产品优化。

社交账号留言

比如在微博上有很多大V或明星要做评控,所以短时间内处理大量评论成为了需求。例如反黑一直是饭圈比较头痛的事情,目前的做法是靠人工进行过滤,Sentiment Analysis就能智能反黑,用数据科学碾压竞争者。

舆情分析

利用公共信息来判断趋势,比如新政策的出台是否受民众喜欢,公众对选举候选人的看法如何。

趋势预测

根据舆论预测选举结果;根据消费者信息指数预测市场趋势;早在2010年,就有学者指出,依靠Twitter公开信息的情感分析来预测股市的涨落,准确率高达87.6%!

Sentiment Analysis的本质是表达一种态度/观点(attitude) ,表达观点包含以下3个元素:

  1. Holder / source of attitude( = 持有观点的人 )
  2. Aspect / target of attitude( = 观点的角度 )
  3. Type of attitude( = 观点的情绪 )
    • positive, negative
    • star rating (⭐ ~ ⭐⭐⭐⭐⭐)
    • hate, dislike, don’t care, Like, love (make choice)

Sentiment Analysis 的常见处理方式有以下几种:

  • docs -based: 整个观点文本直接判断

  • sentences / phrases -based: 将文本拆成句子或短语再进行观点和情绪判断

  • aspects/targets/attributes -based: 先做观点抽取,再做情绪判断。

因此,我们面临的情感分析任务包括如下几类:

  1. Simplest task: Is the attitude of this text positive or negative?

    基于整段文字/句子/短语 直接判断正负向情绪

  2. More complex: Rank the attitude of this text from 1 to 5

    基于整段文字/句子/短语 直接判断情绪层次

  3. Advanced (eg. Aspect-based): Detect the target, source, or complex attitude types

    先判断存在哪些观点的角度,再判断情绪倾向

目前NLP被研究的最多的两种语言是英文和中文,英文在网上搜有很多好用的工具在此不做介绍。这里主要介绍对中文文本的情感分析。

情感倾向分析

一般我们看评价的时候,如果一个商品好评多,我们可能买的更放心。下面是些关于某电影的评价:

公开的sentiment analysis体验接口,可以随意感受一下:

  • 腾讯

  • 百度 (推荐👍虽然不像我的风格,但这块百度做的还可以)

开源/好用的工具

SnowNLP (🔗链接

GitHub上有开源做情感分析的好用的python包,我们来感受一下。首先请确保自己已经 ‘pip install snownlp’ ,对于nlp选手,这个包应该很熟悉了。不仅可以做情感分析,还可以做中文分词、词性标注、提取关键字等等。

1
2
3
4
from snownlp import SnowNLP

s = SnowNLP(u'这个东西真心很赞')
print(s.sentiments) # 0.9769551298267365 positive的概率

非常简单,就3行code解决。再来试试其他:

1
2
3
4
5
6
7
8
s = SnowNLP(u'这个东西真心很赞,速度非常快,隔天到,送货到家,快递员服务态度很好,值得推荐,点个赞!')
print(s.sentiments) # 0.9998864907454681 positive的概率

s = SnowNLP(u'布料不好,不建议购买')
print(s.sentiments) # 0.11886826035520526 positive的概率

s = SnowNLP(u'食物很美味,但是服务员的态度很差劲!总体还可以吧。')
print(s.sentiments) # 0.42427513441222864 positive的概率

第二比第一句的正向评论更多,因此positive的概率也更大了。第三句属于负面评价,因此分数越接近0为负面,接近1为正面。

SnowNLP的优点是可以拿自己的数据去训练这个分类器,缺点是在长文本分析时,尤其是出现多个观点时,会有预测不准的情况。

当评价是长文本,也可以先做分句,再对每个句子进行情感分析:

1
2
3
4
5
6
7
8
9
10
11
12
s = SnowNLP(u'食物很美味,但是服务员的态度很差劲!总体还可以吧。')
for sentence in s.sentences:
print(sentence)
sentc = SnowNLP(sentence)
print(sentc.sentiments)

# 食物很美味
# 0.7625799472162259
# 但是服务员的态度很差劲
# 0.059144753698306296
# 总体还可以吧
# 0.8182792359070481

百度API

这里的APP_ID、API_KEY、SECRET_KEY需要自己申请,传送门:开发指南 。这样就可以免费用百度提供的接口了,目前还挺准的,而且最大可接受2048字节,目前缺点是有QPS=5限制,但也比人判断快多了。

1
2
3
4
5
6
7
8
9
10
11
12
from aip import AipNlp

""" 你的 APPID AK SK """
APP_ID = '15593833'
API_KEY = 'PBW2w1dveS7x3YMecKSZW'
SECRET_KEY = 'AOE75EWZqeI6kM7WMXKesq8i6FzQ'

client = AipNlp(APP_ID, API_KEY, SECRET_KEY)
result=client.sentimentClassify('我真的觉得武林外传超级好看!每个角色都超级喜欢!一年最少看三遍!老白说上一句我就能接下一句!')
print(result)

# {'log_id': 4474874689828720427, 'text': '我真的觉得武林外传超级好看!每个角色都超级喜欢!一年最少看三遍!老白说上一句我就能接下一句!', 'items': [{'negative_prob': 0.0638882, 'sentiment': 2, 'positive_prob': 0.936112, 'confidence': 0.858026}]}

这里的返回结果有negative_prob,表示这段话为负面情绪的概率。sentiment=2表示判断结果为正面情绪,为0表示为负面,为1表示为中立情绪。

如果是批量请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/usr/bin/env  python
# -*- coding: utf-8 -*-

from aip import AipNlp
import pandas as pd
import time

""" 你的 APPID AK SK """
APP_ID = '155934'
API_KEY = 'PBW2w1dveS7x3YcKSZW0V7'
SECRET_KEY = 'AOE75EWZqeI6kM7Kesq8i6FzQruDI'
client = AipNlp(APP_ID, API_KEY, SECRET_KEY)

# 请求文件
source_file = "请求文件路径"
source_df = pd.read_excel(source_file)


comments = []
neg_probs = []
pos_probs = []
confidences = []
sentiments = []
complete_count = 0
# 请求错误统计
err_count = 0
err_comment = []
start_time = time.time()
# 循环请求
i = 0
while i < len(source_df):
comment = source_df["comment_content"][i]
try:
query_result = client.sentimentClassify(comment[:1024])
except Exception as e:
print("query_result:{}".format(query_result))
print("#######请求过程存在问题#######")
err_count += 1
err_comment.append(comment)
i += 1
continue
try:
result = query_result['items'][0]
neg_prob = result['negative_prob']
pos_prob = result['positive_prob']
confidence = result['confidence']
sentiment = result['sentiment']
except KeyError as e:
print("#######请求QPS限制#######")
print("i={}".format(i))
continue
i += 1
comments.append(comment)
neg_probs.append(neg_prob)
pos_probs.append(pos_prob)
confidences.append(confidence)
sentiments.append(sentiment)
complete_count += 1
print("总共:{}条".format(len(source_df)))
print("请求完成: {}条".format(complete_count))
print("完成进度:{}%".format(round(complete_count / len(source_df) * 100, 2)))
cost_mins = (time.time() - start_time) / 60
print("累计用时:{}分钟".format(round(cost_mins, 2)))
avg_query_time = complete_count / cost_mins
# print("每条请求平均用时:{}".format(avg_query_time))
left_mins = (len(source_df) - complete_count - err_count) / avg_query_time
print("预计还需:{}分钟".format(round(left_mins, 2)))
print("\n")

print("所有请求完成!")
print("请求总数量:{}".format(len(source_df)))
print("请求过程中存在问题的数量:{}".format(err_count))



# 保存结果

# 请求成功的结果保存
desti_df = pd.DataFrame()
desti_df["comment"] = comments
desti_df["neg_probs"] = neg_probs
desti_df["pos_probs"] = pos_probs
desti_df["confidences"] = confidences
desti_df["sentiments"] = sentiments
desti_file = "请求结果保存路径"
desti_df.to_excel(desti_file, engine='xlsxwriter')

# 请求失败的结果保存
err_df = pd.DataFrame()
err_file = "请求结果报错保存路径"
err_df["comment"] = err_comment
err_df.to_excel(err_file, engine='xlsxwriter') # 如果请求接口里有奇怪字符,保存文件时就使用, engine='xlsxwriter'

baseline model

关于评价分析最经典的就是kaggle的电影评价题,Bag of Words Meets Bags of Popcorn ,预测一段评论是positive还是negative。稍后会专门为这个比赛写一篇。

可惜整个数据集都是英文的。下面几个为中文的数据集,非常珍贵,供参考:

nlp_chinese_corpus
自然语言处理与信息检索共享平台
爬取商品评论并对商品评论进行情感分类

其他开源项目参考:

评论观点抽取 Aspect-Based

很多时候,观点经常是多角度的。一段评价可能同时有正面情绪和负面情绪,同时表达了多个观点:

食物很美味,但是服务员的态度很差劲!总体还可以吧。

这条评价里对食物的观点是positive的,对服务的观点是negative的,提及了两个维度。此时对整个评价做简单的分类是不够的。

Aspect / target of attitude( = 观点的角度 )

  • single dimension 单个角度
  • many dimensions 多个角度 (food, price, service,……根据不同的产品会有不同的角度)

下面是关于购物评价的 Aspects-based sentiment analysis:

这张图内有两个步骤,首先进行观点抽取,这里有关于价格、服务、口味等观点;其次再进行观点的正负面预测,在最右侧一栏的结果展示里。

给一个百度的观点抽取体验接口:传送门

里面已经有13类行业的各种观点预料训练出来的模型,比如有酒店、美食、房产、汽车等行业。当你把评价输入进去之后,分析结果会把各观点以及情绪都总结出来。

AI Challenger 全球AI挑战赛

2018的AI Challenger有一个是关于观点抽取的:细粒度用户评论情感分析。

would you buy me a coffee☕~
0%