sklearn中lstm_NLP⼊门(⼗)使⽤LSTM进⾏⽂本情感分析情感分析简介
⽂本情感分析(Sentiment Analysis)是⾃然语⾔处理(NLP)⽅法中常见的应⽤,也是⼀个有趣的基本任务,尤其是以提炼⽂本情绪内容为⽬的的分类。它是对带有情感⾊彩的主观性⽂本进⾏分析、处理、归纳和推理的过程。
本⽂将介绍情感分析中的情感极性(倾向)分析。所谓情感极性分析,指的是对⽂本进⾏褒义、贬义、中性的判断。在⼤多应⽤场景下,只分为两类。例如对于“喜爱”和“厌恶”这两个词,就属于不同的情感倾向。
本⽂将详细介绍如何使⽤深度学习模型中的LSTM模型来实现⽂本的情感分析。
⽂本介绍及语料分析
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/")
# 统计句⼦长度及长度出现的频数
df = pd.read_csv('./corpus.csv')
upby('label')['label'].count())
df['length'] = df['evaluation'].apply(lambda x: len(x))
len_df = df.groupby('length').count()
sent_length = len_list()
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")
<(0, quantile, str(quantile))
<(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
dels import Sequential
from keras.preprocessing.sequence import pad_sequences
from keras.layers import LSTM, Dense, Embedding, Dropout
del_selection import train_test_split
ics 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 = [_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'))
modelpile(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_s
hape) 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 = []
import picklelabel = []
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
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论