豆瓣电影短评数据情感分析Baseline

先前已经爬取了豆瓣400w+的电影评论数据(地址:http://moviedata.csuldw.com),为了进一步发挥数据的价值,这次将介绍下如何基于豆瓣影评数据进行评论情感分析,分享一个比较简单的情感分析baseline,后续有机会再将进一步的优化结果分享出来。

数据集处理

原始的电影评论数据共4428475条,样例数据如Fig 1所示,数据里面还夹着一些没有评分的数据,将这些RATING为NaN的过滤掉之后,剩下来的数据有4166704条。

Fig 1. 数据集样例

除了数据评分取值的问题,CONTENT里的文本有的还是繁体,所以在进行情感分析之前,我们还需要对文本的格式统一起来,代码核心部分如下(仅供参考):

1
2
3
4
5
from langconv import *
def traditional2simplified(text):
text = Converter('zh-hans').convert(text)
return text
dataset["CONTENT"] = dataset.CONTENT.apply(lambda x: traditional2simplified(x))

对400多万的文本数据进行分类,乍一看也还算OK,不过在单机上还是有些吃力,所以我们需要对数据进行进一步的去脏以达到缩放的效果,而这一阶段需要做的工作量还是比较多的。

去除干扰评论数据

影评数据的评分RATING评分值为1-5星,这些评分跟评论的相关性还是比较大的。虽然如此,评论里面还是存在很多的干扰数据,笔者对数据集的进行了简单的比较,发现相同的评论,其RATING值居然不一样,这类数据还占了15%以上,真是恐怖如斯!!考虑到数据集的数据量本来就比较大,所以索性对这部分数据直接去掉了,最后剩下3795251条影评数据。

去除过短或过长的数据

在这份电影评论数据集里,文本长度从1-3000+不等,长度过于波动,不太符合短评数据的长度规范。为此,笔者将文本长度限制在了[5,140],上下都取闭区间(豆瓣的短评数据集长度为140),最后得到的数据集3582251条。

情感类别定义

先前提到豆瓣电影评论携带的评分在1-5星,仔细看了评论内容你会发现,1-2星的评论以及4-5星的评论确实很难区分,好在豆瓣给出了1-5星每个星值的意义(1-很差,2-较差,3-还行,4-推荐,5-力荐),所以最后将评论划分为三个:1-2星为消极negative,3星为正常normal,4-5星为正向positive,如此以来,就将评论划分成三个类别了,各个类别的数据量如Fig 2所示。接下来就可以对这个label取值为3类的文本数据进行模型训练与预测了。

Fig 2. 评论Label数据量统计

数据预处理

对于中文文本分词,这里采用的jieba,同时文本数据进行了去停留词处理,代码如下:

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
import jieba
from sklearn.feature_extraction.text import CountVectorizer
def get_stopwords():
stopwords = [line.strip() for line in open('data/stopwords/stopword_normal.txt',encoding='UTF-8').readlines()]
return stopwords
import re
stopwords = get_stopwords()
def text_process(text):
'''
按照下面方式处理字符串
1. 去除标点符号
2. 去掉无用词
3. 返回剩下的词的list
'''
text = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]", "",text)

ltext = jieba.lcut(text)
res_text = []
for word in ltext:
if word not in stopwords:
res_text.append(word)
return res_text

X = dataset.CONTENT
y = dataset.label
bow_transformer = CountVectorizer(analyzer=text_process).fit(X)
X = bow_transformer.transform(X)

通过上面的处理之后,我们可以得到X和y,接下来,可以用这部分数据进行模型训练了。

模型训练与评估

采用sklearn将数据集划分为训练集和测试集,即使比例为9:1,测试数据也有358226t条,一个demo足够了。

1
2
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=99)

由于是多分类,所以就直接采用了MultinomialNB作为baseline,核心代码如下:

1
2
3
4
from sklearn.naive_bayes import MultinomialNB
nb = MultinomialNB()
nb.fit(X_train, y_train)
preds = nb.predict(X_test)

模型评估

得到了预测的preds值之后,直接调用sklearn的metrics里面的方法,就可以轻松地将相关的模型评估指标值计算,代码如下:

1
2
3
from sklearn.metrics import confusion_matrix, classification_report
#根据预测值和真实值计算相关指标
print(classification_report(y_test, preds))

输出结果:

1
2
3
4
5
6
7
8
9
                precision    recall  f1-score   support

-1 0.56 0.56 0.56 70406
0 0.50 0.44 0.47 121276
1 0.66 0.72 0.69 166544

accuracy 0.59 358226
macro avg 0.57 0.57 0.57 358226
weighted avg 0.59 0.59 0.59 358226

可以看出,三个label的平均precision和recall都接近0.6,整体上还是OK的,后续再进一步优化吧,预测方法封装如下:

1
2
3
4
def sentiment_pred(text):
text_transformed = bow_transformer.transform([text])
score = nb.predict(text_transformed)[0]
return score

预测结果如下Fig 3,测试数据样例不要太当真,仅仅作为参考:

Fig 3. 影评预测结果

结束语

各位看客如有需要数据集的可见参考文献[1],其他的就不多说了,情感分类内部细节还有很多待处理,本文仅仅是一个简单的baseline,如果采用深度学习如LSTM进行分类的话,单机上内存可能会不够,所以还需要对数据集进行进一步的处理。OK,就将这个当做是下一个任务项吧!

References

  1. 豆瓣影评数据集:http://moviedata.csuldw.com
  2. http://www.csuldw.com
  3. https://scikit-learn.org