完整演示代码请见本书GitHub上的16-2.py和16-3.py。
1.数据清洗与特征化
从早期的BBS到现在的贴吧、微信和微博,恶意评论一直都挥之不去,有的是网友的无意吐槽,有的是水军的恶意攻击。以往大型互联网企业都需要雇佣大量的运营支撑人员,人工进行筛选,随着互联网的发展,尤其是移动互联网的发展,人工维护几乎成了不可能完成的任务。这次我们尝试使用机器学习的方法来识别恶意评论。这次我们的样本采用Movie Review Data数据集。Movie Review Data数据集包含1000条正面的评论和1000条负面评论,被广泛应用于文本分类尤其是恶意评论识别方面。本书使用其最新的版本,polarity dataset v2.0,详细的介绍请参考第3章内容。
Movie Review Data数据集的每条评论都保存成单独的一个文本文件,正面和负面的评论放置在不同的文件夹下面,使用词袋模型将文本向量化。
读取文件,把每个文件转换成一个字符串:
def load_one_file(filename): x="" with open(filename) as f: for line in f: x+=line return x
遍历读取文件夹下全部文件:
def load_files(rootdir,label): list = os.listdir(rootdir) x=[] y=[] for i in range(0, len(list)): path = os.path.join(rootdir, list[i]) if os.path.isfile(path): print "Load file %s" % path y.append(label) x.append(load_one_file(path)) return x,y
根据不同文件夹,标记为正面和负面,其中正面评论标记为0,负面评论标记为1:
def load_data(): x=[] y=[] x1,y1=load_files("../data/movie-review-data/review_polarity/txt_sentoken/pos/",0) x2,y2=load_files("../data/movie-review-data/review_polarity/txt_sentoken/neg/", 1) x=x1+x2 y=y1+y2 return x,y
使用词袋模型将数据向量化,并且使用train_test_split将样本随机划分成训练集合和测试集合,分配比例为0.4:
x,y=load_data() x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.4, random_state=0) vp = learn.preprocessing.VocabularyProcessor(max_document_length=MAX_DOCUMENT_LENGTH, min_frequency=1) vp.fit(x) x_train = np.array(list(vp.transform(x_train))) x_test = np.array(list(vp.transform(x_test))) n_words=len(vp.vocabulary_) print('Total words: %d' % n_words)
2.训练样本
NB算法在文本分类领域有着广泛的应用,作为对比测试,首先使用NB算法:
gnb = GaussianNB() gnb.fit(x_train, y_train)
识别页面评论过程如图16-8所示。
图16-8 RNN/NB识别负面评论的过程
RNN特别适合检测时序型数据,所以需要将评论转换成时序数据,截取文件的前100个单词作为一个序列,每个单词又由词袋模型进行编码,标记数据使用one-hot编码,如图16-9所示。
图16-9 评论内容转换成RNN可以处理的时序向量
trainX = pad_sequences(trainX, maxlen=100, value=0.) testX = pad_sequences(testX, maxlen=100, value=0.) trainY = to_categorical(trainY, nb_classes=2) testY = to_categorical(testY, nb_classes=2)
构造RNN网络,输入层长度为100,embedding输入的数据维度为词袋的词汇表的长度n_words,输出的数据维度定义为128,LSTM层随机筛选80%的数据传递给下一层:
net = tflearn.input_data([None, 100]) net = tflearn.embedding(net, input_dim=n_words, output_dim=128) net = tflearn.lstm(net, 128, dropout=0.8)
全连接层激活函数使用softmax函数,输出数据维度为2,优化使用adam算法,学习速率为0.001:
net = tflearn.fully_connected(net, 2, activation='softmax') net = tflearn.regression(net, optimizer='adam', learning_rate=0.001, loss='categorical_crossentropy') model = tflearn.DNN(net, tensorboard_verbose=0) model.fit(trainX, trainY, validation_set=(testX, testY), show_metric=True, batch_size=32)
3.验证效果
NB算法比对测试数据集的预测结果与标记数据,准确率为51%左右:
y_predict = gnb.fit(x_train, y_train).predict(x_test) score = metrics.accuracy_score(y_test, y_predict) print('NB Accuracy: {0:f}'.format(score))
RNN算法在fit函数中直接指定了测试数据集合(testX,testY):
model.fit(trainX, trainY, validation_set=(testX, testY), show_metric=True, batch_size=32)
运行结果如图16-10所示,准确率61%左右,不是特别理想。
图16-10 RNN识别评论结果