NLP|对商品评论进行情感分析

Sentiment Analysis

Posted by Jinga on November 4, 2019

基于fastText对商品评论进行情感分析

1.问题背景

在电商平台中,很多用户都会基于自己的购物体验对商品进行评分和评论.但有些用户只给出了评论而没有评分,没有了评分的量化标准,这给商家进行数据运营与选品决策带来了困难.如何根据商品评论估计出相对应的评分,这是情感分析的问题,我们可以用fastText文本分类器来快速解决.

2. fastText简介

fastText是FAIR(Facebook AI Research)于2016年开源的一个词向量与文本分类工具,主要优点是能够取得与深度神经网络相媲美的分类精度,同时训练速度比深度神经网络快几个数量级,节约了不小的训练成本,果然是名副其实fastText.

3. fastText安装

$ git clone https://github.com/facebookresearch/fastText.git
$ cd fastText
$ sudo python setup.py install

4. 准备数据

下载Yelp商品评论数据(JSON格式)

Yelp是美国著名商户点评网站,提供了470万的用户评论数据以作科学研究.Yelp采用的是五星级评分,用户评分和评论的例子如下:

yelp.png

下载解压后会得到数据reviews.json(大约5.3G),每行是个json对象,格式如下:

{
  "review_id": "abc123",
  "user_id": "xyz123",
  "business_id": "1234",
  "stars": 5,
  "date":" 2019-01-01",
  "text": "This restaurant is great!",
  "useful":0,
  "funny":0,
  "cool":0
}

但是fastText要求输入的数据需要有个标签前缀__label__YOURLABEL,所以我们要对reviews.json的数据进行预处理,像上面的评论要转换为

__label__5 This restaurant is great!

5. 数据预处理

import json
from pathlib import Path
import re
import random

reviews_data = Path("yelp_dataset") / "yelp_academic_dataset_review.json"
training_data = Path("fasttext_dataset_training.txt")
test_data = Path("fasttext_dataset_test.txt")

# 按照9:1比例随机划分的训练数据和测试数据,percent_test_data为测试集对总数据集的占比
percent_test_data = 0.10

def strip_formatting(string):
    string = string.lower()
    string = re.sub(r"([.!?,'/()])", r" \1 ", string)
    return string

with reviews_data.open() as input, \
     training_data.open("w") as train_output, \
     test_data.open("w") as test_output:

    for line in input:
        review_data = json.loads(line)

        rating = review_data['stars']
        text = review_data['text'].replace("\n", " ")
        text = strip_formatting(text)

        fasttext_line = "__label__{} {}".format(rating, text)

        if random.random() <= percent_test_data:
            test_output.write(fasttext_line + "\n")
        else:
            train_output.write(fasttext_line + "\n")

将上面代码保存为dataPre.py,运行后会得到按照9:1比例随机划分的训练数据和测试数据(fasttext_dataset_training.txt & fasttext_dataset_test.txt)

6. 训练模型

import fasttext
model = fasttext.train_supervised(input="fasttext_dataset_training.txt")
model.save_model("model_reviews.bin
")

训练模型并保存模型为model_reviews.bin

sentitrain.png

7. 测试模型

import fasttext

def print_results(N, p, r):
    print("样本数N\t" + str(N))
    print("精确率P@{}\t{:.3f}".format(1, p))
    print("召回率R@{}\t{:.3f}".format(1, r))

model = fasttext.load_model("model_reviews.bin")

print_results(*model.test('fasttext_dataset_test.txt'))

fast.png

运行后得到测试结果精确率是69.6%,还是有很大的提升空间的:joy:

8. 优化模型

在之前的模型训练中是不考虑单词的顺序的,每个单词在句子中是独立的,但实际情形不是这样的,往往需要考虑上下文,这个时候我们可以用参数wordNgrams来进行改进,把N个单词捆绑在一起进行训练.考虑到时间成本,我们取wordNgrams=2

import fasttext

model = fasttext.train_supervised(input="fasttext_dataset_training.txt", lr=0.8, epoch=25, wordNgrams=2)
model.save_model("model_reviews.bin")
def print_results(N, p, r):
    print("样本数N\t" + str(N))
    print("精确率P@{}\t{:.3f}".format(1, p))
    print("召回率R@{}\t{:.3f}".format(1, r))
  
print_results(*model.test('fasttext_dataset_test.txt'))

better.png

精确率为70.2%,只提高了0.6%,模型仍需要优化啊

我们随机找几个评论预测一下星级评分

import fasttext



model = fasttext.load_model("model_reviews.bin")
sent = input("Please input:")

test = model.predict(sent)
s = float('%.4f' % test[1])



if test[0] =="('__label__1.0',)":
	print("Star rating:☆ \nConfidence: % s%%" % (s*100))
elif test[0] =="('__label__2.0',)":
	print("star rating:☆☆ \nConfidence: % s%%" % (s*100))
elif test[0] =="('__label__3.0',)":
	print("star rating:☆☆☆ \nConfidence: % s%%" % (s*100))
elif test[0] =="('__label__4.0',)":
	print("star rating:☆☆☆☆ \nConfidence: % s%%" % (s*100))
else:
	print("star rating:☆☆☆☆☆ \nConfidence: % s%%" % (s*100))

predict.png

参考:
  1. Text Classification is Your New Secret Weapon
  2. fastText supervised tutorial