情感分析简介

  文本情感分析(Sentiment Analysis)是自然语言处理(NLP)方法中常见的应用,也是一个有趣的基本任务,尤其是以提炼文本情绪内容为目的的分类。它是对带有情感色彩的主观性文本进行分析、处理、归纳和推理的过程。

  本文将介绍情感分析中的情感极性(倾向)分析。所谓情感极性分析,指的是对文本进行褒义、贬义、中性的判断。在大多应用场景下,只分为两类。例如对于“喜爱”和“厌恶”这两个词,就属于不同的情感倾向。

  本文将详细介绍如何使用深度学习模型中的LSTM模型来实现文本的情感分析。

文本介绍及语料分析

  我们以某电商网站中某个商品的评论作为语料(corpus.csv),该数据集的下载网址为:https://github.com/renjunxiang/Text-Classification/blob/master/TextClassification/data/data_single.csv ,该数据集一共有4310条评论数据,文本的情感分为两类:“正面”和“反面”,该数据集的前几行如下:

evaluation,label

用了一段时间,感觉还不错,可以,正面

电视非常好,已经是家里的第二台了。第一天下单,第二天就到本地了,可是物流的人说车坏了,一直催,客服也帮着催,到第三天下午5点才送过来。父母年纪大了,买个大电视画面清晰,趁着耳朵还好使,享受几年。,正面

电视比想象中的大好多,画面也很清晰,系统很智能,更多功能还在摸索中,正面

不错,正面

用了这么多天了,感觉还不错。夏普的牌子还是比较可靠。希望以后比较耐用,现在是考量质量的时候。,正面

物流速度很快,非常棒,今天就看了电视,非常清晰,非常流畅,一次非常完美的购物体验,正面

非常好,客服还特意打电话做回访,正面

物流小哥不错,辛苦了,东西还没用,正面

送货速度快,质量有保障,活动价格挺好的。希望用的久,不出问题。,正面

  接着我们需要对语料做一个简单的分析:

  • 数据集中的情感分布;
  • 数据集中的评论句子长度分布。

  使用以下Python脚本,我们可以统计出数据集中的情感分布以及评论句子长度分布。

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import font_manager
from itertools import accumulate # 设置matplotlib绘图时的字体
my_font = font_manager.FontProperties(fname="/Library/Fonts/Songti.ttc") # 统计句子长度及长度出现的频数
df = pd.read_csv('./corpus.csv')
print(df.groupby('label')['label'].count()) df['length'] = df['evaluation'].apply(lambda x: len(x))
len_df = df.groupby('length').count()
sent_length = len_df.index.tolist()
sent_freq = len_df['evaluation'].tolist() # 绘制句子长度及出现频数统计图
plt.bar(sent_length, sent_freq)
plt.title("句子长度及出现频数统计图", fontproperties=my_font)
plt.xlabel("句子长度", fontproperties=my_font)
plt.ylabel("句子长度出现的频数", fontproperties=my_font)
plt.savefig("./句子长度及出现频数统计图.png")
plt.close() # 绘制句子长度累积分布函数(CDF)
sent_pentage_list = [(count/sum(sent_freq)) for count in accumulate(sent_freq)] # 绘制CDF
plt.plot(sent_length, sent_pentage_list) # 寻找分位点为quantile的句子长度
quantile = 0.91
#print(list(sent_pentage_list))
for length, per in zip(sent_length, sent_pentage_list):
if round(per, 2) == quantile:
index = length
break
print("\n分位点为%s的句子长度:%d." % (quantile, index)) # 绘制句子长度累积分布函数图
plt.plot(sent_length, sent_pentage_list)
plt.hlines(quantile, 0, index, colors="c", linestyles="dashed")
plt.vlines(index, 0, quantile, colors="c", linestyles="dashed")
plt.text(0, quantile, str(quantile))
plt.text(index, 0, str(index))
plt.title("句子长度累积分布函数图", fontproperties=my_font)
plt.xlabel("句子长度", fontproperties=my_font)
plt.ylabel("句子长度累积频率", fontproperties=my_font)
plt.savefig("./句子长度累积分布函数图.png")
plt.close()

输出的结果如下:

label
正面 1908
负面 2375
Name: label, dtype: int64 分位点为0.91的句子长度:183.

可以看到,正反面两类情感的比例差不多。句子长度及出现频数统计图如下:

句子长度累积分布函数图如下:

可以看到,大多数样本的句子长度集中在1-200之间,句子长度累计频率取0.91分位点,则长度为183左右。

使用LSTM模型

  接着我们使用深度学习中的LSTM模型来对上述数据集做情感分析,笔者实现的模型框架如下:

完整的Python代码如下:

# -*- coding: utf-8 -*-

import pickle
import numpy as np
import pandas as pd
from keras.utils import np_utils, plot_model
from keras.models import Sequential
from keras.preprocessing.sequence import pad_sequences
from keras.layers import LSTM, Dense, Embedding, Dropout
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score # 导入数据
# 文件的数据中,特征为evaluation, 类别为label.
def load_data(filepath, input_shape=20):
df = pd.read_csv(filepath) # 标签及词汇表
labels, vocabulary = list(df['label'].unique()), list(df['evaluation'].unique()) # 构造字符级别的特征
string = ''
for word in vocabulary:
string += word vocabulary = set(string) # 字典列表
word_dictionary = {word: i+1 for i, word in enumerate(vocabulary)}
with open('word_dict.pk', 'wb') as f:
pickle.dump(word_dictionary, f)
inverse_word_dictionary = {i+1: word for i, word in enumerate(vocabulary)}
label_dictionary = {label: i for i, label in enumerate(labels)}
with open('label_dict.pk', 'wb') as f:
pickle.dump(label_dictionary, f)
output_dictionary = {i: labels for i, labels in enumerate(labels)} vocab_size = len(word_dictionary.keys()) # 词汇表大小
label_size = len(label_dictionary.keys()) # 标签类别数量 # 序列填充,按input_shape填充,长度不足的按0补充
x = [[word_dictionary[word] for word in sent] for sent in df['evaluation']]
x = pad_sequences(maxlen=input_shape, sequences=x, padding='post', value=0)
y = [[label_dictionary[sent]] for sent in df['label']]
y = [np_utils.to_categorical(label, num_classes=label_size) for label in y]
y = np.array([list(_[0]) for _ in y]) return x, y, output_dictionary, vocab_size, label_size, inverse_word_dictionary # 创建深度学习模型, Embedding + LSTM + Softmax.
def create_LSTM(n_units, input_shape, output_dim, filepath):
x, y, output_dictionary, vocab_size, label_size, inverse_word_dictionary = load_data(filepath)
model = Sequential()
model.add(Embedding(input_dim=vocab_size + 1, output_dim=output_dim,
input_length=input_shape, mask_zero=True))
model.add(LSTM(n_units, input_shape=(x.shape[0], x.shape[1])))
model.add(Dropout(0.2))
model.add(Dense(label_size, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) plot_model(model, to_file='./model_lstm.png', show_shapes=True)
model.summary() return model # 模型训练
def model_train(input_shape, filepath, model_save_path): # 将数据集分为训练集和测试集,占比为9:1
# input_shape = 100
x, y, output_dictionary, vocab_size, label_size, inverse_word_dictionary = load_data(filepath, input_shape)
train_x, test_x, train_y, test_y = train_test_split(x, y, test_size = 0.1, random_state = 42) # 模型输入参数,需要自己根据需要调整
n_units = 100
batch_size = 32
epochs = 5
output_dim = 20 # 模型训练
lstm_model = create_LSTM(n_units, input_shape, output_dim, filepath)
lstm_model.fit(train_x, train_y, epochs=epochs, batch_size=batch_size, verbose=1) # 模型保存
lstm_model.save(model_save_path) N = test_x.shape[0] # 测试的条数
predict = []
label = []
for start, end in zip(range(0, N, 1), range(1, N+1, 1)):
sentence = [inverse_word_dictionary[i] for i in test_x[start] if i != 0]
y_predict = lstm_model.predict(test_x[start:end])
label_predict = output_dictionary[np.argmax(y_predict[0])]
label_true = output_dictionary[np.argmax(test_y[start:end])]
print(''.join(sentence), label_true, label_predict) # 输出预测结果
predict.append(label_predict)
label.append(label_true) acc = accuracy_score(predict, label) # 预测准确率
print('模型在测试集上的准确率为: %s.' % acc) if __name__ == '__main__':
filepath = './corpus.csv'
input_shape = 180
model_save_path = './corpus_model.h5'
model_train(input_shape, filepath, model_save_path)

对上述模型,共训练5次,训练集和测试集比例为9:1,输出的结果为:

......
Epoch 5/5
......
3424/3854 [=========================>....] - ETA: 2s - loss: 0.1280 - acc: 0.9565
3456/3854 [=========================>....] - ETA: 1s - loss: 0.1274 - acc: 0.9569
3488/3854 [==========================>...] - ETA: 1s - loss: 0.1274 - acc: 0.9570
3520/3854 [==========================>...] - ETA: 1s - loss: 0.1287 - acc: 0.9568
3552/3854 [==========================>...] - ETA: 1s - loss: 0.1290 - acc: 0.9564
3584/3854 [==========================>...] - ETA: 1s - loss: 0.1284 - acc: 0.9568
3616/3854 [===========================>..] - ETA: 1s - loss: 0.1284 - acc: 0.9569
3648/3854 [===========================>..] - ETA: 0s - loss: 0.1278 - acc: 0.9572
3680/3854 [===========================>..] - ETA: 0s - loss: 0.1271 - acc: 0.9576
3712/3854 [===========================>..] - ETA: 0s - loss: 0.1268 - acc: 0.9580
3744/3854 [============================>.] - ETA: 0s - loss: 0.1279 - acc: 0.9575
3776/3854 [============================>.] - ETA: 0s - loss: 0.1272 - acc: 0.9579
3808/3854 [============================>.] - ETA: 0s - loss: 0.1279 - acc: 0.9580
3840/3854 [============================>.] - ETA: 0s - loss: 0.1281 - acc: 0.9581
3854/3854 [==============================] - 18s 5ms/step - loss: 0.1298 - acc: 0.9577
......
给父母买的,特意用了一段时间再来评价,电视非常好,没有坏点和损坏,界面也很简洁,便于操作,稍微不足就是开机会比普通电视慢一些,这应该是智能电视的通病吧,如果可以希望微鲸大大可以更新系统优化下开机时间~电视真的很棒,性价比爆棚,值得大家考虑购买。 客服很细心,快递小哥很耐心的等我通电验货,态度非常好。 负面 正面
长须鲸和海狮回答都很及时,虽然物流不够快但是服务不错电视不错,对比了乐视小米和微鲸论性价比还是微鲸好点 负面 负面
所以看不到4k效果,但是应该可以。 自带音响,中规中矩吧,好像没有别人说的好。而且,到现在没连接上我的漫步者,这个非常不满意,因为看到网上说好像普通3.5mm的连不上或者连上了声音小。希望厂家接下来开发的电视有改进。不知道我要不要换个音响。其他的用用再说。 放在地上的是跟我混了两年的tcl,天气受潮,修了一次,下岗了。 最后,我也觉得底座不算太稳,凑合着用。 负面 负面
电视机一般,低端机不要求那么高咯。 负面 负面
很好,两点下单上午就到了,服务很好。 正面 正面
帮朋友买的,好好好好好好好好 正面 正面
......
模型在测试集上的准确率为: 0.9020979020979021.

可以看到,该模型在训练集上的准确率为95%以上,在测试集上的准确率为90%以上,效果还是相当不错的。

模型预测

  接着,我们利用刚刚训练好的模型,对新的数据进行测试。笔者随机改造上述样本的评论,然后预测其情感倾向。情感预测的Python代码如下:

# -*- coding: utf-8 -*-

# Import the necessary modules
import pickle
import numpy as np
from keras.models import load_model
from keras.preprocessing.sequence import pad_sequences # 导入字典
with open('word_dict.pk', 'rb') as f:
word_dictionary = pickle.load(f)
with open('label_dict.pk', 'rb') as f:
output_dictionary = pickle.load(f) try:
# 数据预处理
input_shape = 180
sent = "电视刚安装好,说实话,画质不怎么样,很差!"
x = [[word_dictionary[word] for word in sent]]
x = pad_sequences(maxlen=input_shape, sequences=x, padding='post', value=0) # 载入模型
model_save_path = './sentiment_analysis.h5'
lstm_model = load_model(model_save_path) # 模型预测
y_predict = lstm_model.predict(x)
label_dict = {v:k for k,v in output_dictionary.items()}
print('输入语句: %s' % sent)
print('情感预测结果: %s' % label_dict[np.argmax(y_predict)]) except KeyError as err:
print("您输入的句子有汉字不在词汇表中,请重新输入!")
print("不在词汇表中的单词为:%s." % err)

输出结果如下:

输入语句: 电视刚安装好,说实话,画质不怎么样,很差!
情感预测结果: 负面

  让我们再尝试着测试一些其他的评论:

输入语句: 物超所值,真心不错
情感预测结果: 正面
输入语句: 很大很好,方便安装!
情感预测结果: 正面
输入语句: 卡,慢,死机,闪退。
情感预测结果: 负面
输入语句: 这种货色就这样吧,别期待怎样。
情感预测结果: 负面
输入语句: 啥服务态度码,出了事情一个推一个,送货安装还收我50
情感预测结果: 负面
输入语句: 京东服务很好!但我买的这款电视两天后就出现这样的问题,很后悔买了这样的电视
情感预测结果: 负面
输入语句: 产品质量不错,就是这位客服的态度十分恶劣,对相关服务不予解释说明,缺乏耐心,
情感预测结果: 负面
输入语句: 很满意,电视非常好。护眼模式,很好,也很清晰。
情感预测结果: 负面

总结

  当然,该模型并不是对一切该商品的评论都会有好的效果,还是应该针对特定的语料去训练,去预测。

  本文主要介绍了LSTM模型在文本情感分析方面的应用,该项目已上传Github,地址为: https://github.com/percent4/Sentiment_Analysis

注意:不妨了解下笔者的微信公众号: Python爬虫与算法(微信号为:easy_web_scrape), 欢迎大家关注~

参考文献

  1. Python机器学习 -- NLP情感分析:https://blog.csdn.net/qq_38328378/article/details/81198322
  2. 数据集来源:https://github.com/renjunxiang/Text-Classification/blob/master/TextClassification/data/data_single.csv

NLP入门(十)使用LSTM进行文本情感分析的更多相关文章

  1. LSTM实现中文文本情感分析

    1. 背景介绍 文本情感分析是在文本分析领域的典型任务,实用价值很高.本模型是第一个上手实现的深度学习模型,目的是对深度学习做一个初步的了解,并入门深度学习在文本分析领域的应用.在进行模型的上手实现之 ...

  2. LSTM 文本情感分析/序列分类 Keras

    LSTM 文本情感分析/序列分类 Keras 请参考 http://spaces.ac.cn/archives/3414/   neg.xls是这样的 pos.xls是这样的neg=pd.read_e ...

  3. 基于 Spark 的文本情感分析

    转载自:https://www.ibm.com/developerworks/cn/cognitive/library/cc-1606-spark-seniment-analysis/index.ht ...

  4. TensorFlow实现文本情感分析详解

    http://c.biancheng.net/view/1938.html 前面我们介绍了如何将卷积网络应用于图像.本节将把相似的想法应用于文本. 文本和图像有什么共同之处?乍一看很少.但是,如果将句 ...

  5. TensorFlow文本情感分析实现

    TensorFlow文本情感分析实现 前面介绍了如何将卷积网络应用于图像.本文将把相似的想法应用于文本. 文本和图像有什么共同之处?乍一看很少.但是,如果将句子或文档表示为矩阵,则该矩阵与其中每个单元 ...

  6. NLP入门(十一)从文本中提取时间

      在我们的日常生活和工作中,从文本中提取时间是一项非常基础却重要的工作,因此,本文将介绍如何从文本中有效地提取时间.   举个简单的例子,我们需要从下面的文本中提取时间: 6月28日,杭州市统计局权 ...

  7. 文本情感分析(一):基于词袋模型(VSM、LSA、n-gram)的文本表示

    现在自然语言处理用深度学习做的比较多,我还没试过用传统的监督学习方法做分类器,比如SVM.Xgboost.随机森林,来训练模型.因此,用Kaggle上经典的电影评论情感分析题,来学习如何用传统机器学习 ...

  8. 文本情感分析(二):基于word2vec、glove和fasttext词向量的文本表示

    上一篇博客用词袋模型,包括词频矩阵.Tf-Idf矩阵.LSA和n-gram构造文本特征,做了Kaggle上的电影评论情感分类题. 这篇博客还是关于文本特征工程的,用词嵌入的方法来构造文本特征,也就是用 ...

  9. 机器学习 - LSTM应用之情感分析

    1. 概述 在情感分析的应用领域,例如判断某一句话是positive或者是negative的案例中,咱们可以通过传统的standard neuro network来作为解决方案,但是传统的神经网络在应 ...

随机推荐

  1. 编写你的第一个django应用程序2

    从1停止的地方开始,我们将设置数据库,创建您的第一个模型,并快速介绍django自动生成的管理站点 数据库设置 现在,打开mysite/settings.py.这是一个普通的python模块,其中模块 ...

  2. 顽石系列:Java技术面试

    顽石系列:Java技术面试 JDBC相关 1.Statement与PreparedStatement的区 别,什什么是SQL注⼊入,如何防⽌止SQL注⼊? PreparedStatement支持动态设 ...

  3. 从动态库的def文件生成lib文件

    以sqlite3为例,下载的文件中只有def文件,没有lib文件,想使用静态方式调用dll的情况下,就需要额外的.h文件和.lib文件存在. .h文件可以从官方下载的sqlite-amalgamati ...

  4. mini2440移植uboot 2011.03(下)

    参考博文: <u-boot-2011.03在mini2440/micro2440上的移植> 移植(五)添加nand支持: host@debian:~/soft/mini2440/u-boo ...

  5. 主成分分析(PCA)与SVD奇异值分解

      主要参考:https://www.zhihu.com/question/38417101/answer/94338598 http://blog.jobbole.com/88208/ 先说下PCA ...

  6. mooc_java Socket

    Socket通信,TCP协议是面向连接,可靠的,有序的,以字节流的方式发送数据:基于TCP协议实现网络通信的类客户端的Socket类 服务器端的ServerSocket类 -------------- ...

  7. SSH中的Hibernate

    SSH中的Hibernate 就是DAO连接数据库对数据进行实际操作,做了架构简化,对数据库的操作.

  8. RabbitMQ消息队列随笔

    本文权当各位看官对RabbitMQ的基本概念以及使用场景有了一定的了解,如果你还对它所知甚少或者只是停留在仅仅是听说过,建议你先看看这篇文章,在对RabbitMQ有了基本认识后,我们正式开启我们的Ra ...

  9. kmp算法模板及理解

    kmp算法是复杂度为O(n+m)的字符串匹配算法; 首先kmp算法的核心是在模式串中获得next数组,这个数组表示模式串的子串的前缀和后缀相同的最长长度; 这样在匹配的过程中如果指到不匹配的位置,模式 ...

  10. C语言中的文件操作

    按照字符的方式读取文件 按照行的方式读取文件 按照数据块的方式读取文件 按照格式化的方式读取文件 文件分类 记录文件:具有一定的结构记录组成,分为定长和不定长两种方式 流式文件:按照一个字符一个字符( ...