一、数据的预处理
1、首先将从网上搜集已经标注好的数据集包含的领域有书籍、酒店、计算机、牛奶、手机、热水器,积极的评论10679条标注为1,消极的评论10428条标注为0,添加完标记后将其合并。这里使用Python
来完成处理,用到的第三方库有numpy
和pandas
。处理的代码如下:
pos = pd.read_excel('./pos.xls',header=None)
pos['label'] = 1;
neg = pd.read_excel('./neg.xls',header=None)
neg['label'] = 0
all_ = pos.append(neg,ignore_index=True)
2、中文切词,采用开源库jieba
把每条评论进行切词。注意这里使用深度学习的方法来训练模型,所以去除一些停用词。共计词汇数目1353755
all_['words'] = all_[0].apply(lambda s: list(jieba.cut(s)))
3、将词汇进行向量转化,比如有三个词汇"你","好","漂亮","风趣",'假如用数字来表示他们1,2,3,4。那么"你好风趣"整个句子的表示方式为[1,2,4],而"你好漂亮"的向量表示为[1,2,3]。基于上一步我们切词得到的词汇1353755
条进行词频统计,统计完我们需要做一些处理:去除重复的词条,去重后剩余50921
条词汇。为了加快我们训练的速度,我们这里对50921
条词汇进一步处理:过滤掉频次少于5
的词汇,处理后剩余词汇14321
条。然后将每个词语从1-14321进行编号,另外空格符' '标号为0。
maxlen = 100 #截断词数
min_count = 5 #出现次数少于该值的词扔掉。这是最简单的降维方法
content = []
for i in all_['words']:
content.extend(i)
# print(len(set(content)))
abc = pd.Series(content).value_counts()
abc = abc[abc >= min_count]
# print(len(abc))
abc[:] = list(range(1, len(abc)+1))
abc[''] = 0 #添加空字符串用来补全
word_set = set(abc.index)
4、将每条评论用向量来表示,为了统一X(X为训练的输入集合)的格式,我们这里将每条评论都是100个词汇组成,不够100的用空格的来补全,超过的则截取。
def doc2num(s, maxlen):
s = [i for i in s if i in word_set]
s = s[:maxlen] + ['']*max(0, maxlen-len(s))
print(s)
return list(abc[s])
all_['doc2num'] = all_['words'].apply(lambda s: doc2num(s, maxlen))
二、训练模型并保存
使用keras
基于LSTM搭建一个深度模型,使用15000条评论进行训练,用剩下的评论的做验证集。验证的准确率有81.13%。
# #手动打乱数据
idx = list(range(len(all_)))
np.random.shuffle(idx)
all_ = all_.loc[idx]
#
# #按keras的输入要求来生成数据
x = np.array(list(all_['doc2num']))
y = np.array(list(all_['label']))
y = y.reshape((-1, 1)) # 调整标签形状
# print(x)
# print(x.shape)
from keras.models import Sequential
from keras.layers import Dense, Activation, Dropout, Embedding
from keras.layers import LSTM
# 建立模型
model = Sequential()
model.add(Embedding(len(abc), 256, input_length=maxlen))
model.add(LSTM(128))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy',
optimizer='adam',
metrics=['accuracy'])
batch_size = 128
train_num = 15000
model.predict()
model.fit(x[:train_num], y[:train_num], batch_size=batch_size, epochs=30)
score = model.evaluate(x[train_num:], y[train_num:], batch_size=batch_size)
model.save('./commemnt.h5')
三、使用衡山负面评论书籍来验证模型的准确率
使用衡山负面游记评论来验证,其验证结果正确率为59.6%
,正确不太理想,出现的原因可能有:1、训练集合中没有包含旅游评论的数据。2、词频过滤设置为5和假设每条评论最多为100个词汇的假设存在问题。3、词向量的转化方式。4、算法和超参数需要调整
from keras.models import load_model
import jieba
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
model = load_model('./commemnt.h5')
print(model)
def load_list(path):
with open(path) as fp:
arr = [ w.strip() for w in fp.readlines()]
return arr
# 1.加载所有的评论
# comments = load_list('./neg_hengshan.txt')
comments = pd.read_excel('./neg.xls',header=None)[0].values
# 2.将所有评论进行切词
cut_words = []
for comment in comments:
words = []
for w in jieba.cut(comment[2:-2]):
words.append(w)
cut_words.append(words)
pos = pd.read_excel('./pos.xls',header=None)
pos['label'] = 1;
neg = pd.read_excel('./neg.xls',header=None)
neg['label'] = 0
all_ = pos.append(neg,ignore_index=True)
all_['words'] = all_[0].apply(lambda s: list(jieba.cut(s)))
#
#
#
maxlen = 100 #截断词数
min_count = 5 #出现次数少于该值的词扔掉。这是最简单的降维方法
content = []
for i in all_['words']:
content.extend(i)
abc = pd.Series(content).value_counts()
abc = abc[abc >= min_count]
abc[:] = list(range(1, len(abc)+1))
abc[''] = 0 #添加空字符串用来补全
word_set = set(abc.index)
def doc2num(s, maxlen):
s = [i for i in s if i in word_set]
s = s[:maxlen] + ['']*max(0, maxlen-len(s))
# print(abc[s])
return list(abc[s])
print(cut_words[0])
arr = [ doc2num(w,100) for w in cut_words]
# print(arr)
#
#
#
# # print(all_)
#
# # # #手动打乱数据
# # idx = list(range(len(all_)))
# # np.random.shuffle(idx)
# # all_ = all_.loc[idx]
# #
# # #按keras的输入要求来生成数据
x = np.array(arr)
#
# print(x)
#
#
#
arr = model.predict(x,steps=1)
correct_results = []
for w in arr:
if w < 0.5:
correct_results.append(correct_results)
print('负面评论的比例为:{}'.format(len(correct_results)/len(arr)))
# plt.scatter(arr,range(0,len(arr)),label='test')
# plt.xlabel('x')
# plt.ylabel('y')
# plt.title('test')
# plt.legend()
# plt.show()
网友评论