基于双向 GRU 的文本分类 Python 算法实战

Posted 我爱Python数据挖掘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于双向 GRU 的文本分类 Python 算法实战相关的知识,希望对你有一定的参考价值。

大家好,文本数据的处理,对于一个风控策略或者算法,我觉得是必须要掌握的技能,有人说,我的风控并不涉及到文本?我觉得这片面了,在非内容风控领域,文本知识也是非常有用的。

用户昵称、地址啥的,这种绝大部分风控场景都能遇到;关系网络的节点向量化,基本也是文本处理的思路;行为序列,也能用文本的知识去处理,能捕捉非常有趣模式。

去年就已经写的差不多了,现在整理好慢慢更新,本系列主要介绍了风控场景下文本分类的基本方法,对抗文本变异,包括传统的词袋模型、循环神经网络,也有常用于计算机视觉任务的卷积神经网络,以及 RNN + CNN,试验完一遍,基本能搞定大部分的文本分类以及文本变异对抗问题。

今天使用双向GRU对文本进行分类,喜欢记得收藏、关注、点赞。完整代码,获取如下

目前开通了技术交流群,群友已超过2000人,添加时最好的备注方式为:来源+兴趣方向,方便找到志同道合的朋友
方式、添加微信号:dkl88191,备注:来自CSDN
方式、微信搜索公众号:Python学习与数据挖掘,后台回复:加群

一、原理介绍

RNN 可能看起来很可怕,尽管它们因为复杂而难以理解,但非常有趣。RNN 模型封装了一个非常漂亮的设计,以克服传统神经网络在处理序列数据(文本、时间序列、视频、DNA 序列等)时的短板。

RNN 是一系列神经网络的模块,它们彼此连接像锁链一样,每一个都将消息向后传递,强烈推荐大家从 Colah 的博客中深入了解它的内部机制,下面的图就来源于此。

我们要处理的序列类型是文本数据。对意义而言,单词顺序很重要。RNN 考虑到了这一点,它可以捕捉长期依赖关系。

二、数据集和预处理

本文用一个风险弹幕数据集做实验,该数据集包含19670条明细数据,每一行都用 1(垃圾文本)和 0(正常文本)进行了标记。

数据集地址:https://github.com/LebronGG/textcnn/blob/master/data/cnews/train.txt,自己需要简单处理下,负向-1,正向-0即可。也可以后台回复【弹幕】获取

目标: 针对直播间中存在的大量涉黄涉暴弹幕,进行垃圾分类,将弹幕中不合法的内容进行识别并屏蔽。

正常弹幕示例

新人主播,各位老板多多关注ᚠᚠᚠ 0

50077你卖我 0

看看五雷咒的威力 0

垃圾弹幕示例

网站++沜买的私聊我 1

安 KMD555 买-P-微 1

抠逼加薇2928046748抠逼加薇2928046748抠逼。 1

数据读取和查看

import os 
import pandas as pd
path  = '/Users/wuzhengxiang/Documents/DataSets/TextCnn'
os.chdir(path)
data = pd.read_csv('text_all.csv')

#对数据进行随机打乱
data = data.sample(frac=1, random_state=42)
print(data.shape)
(19670, 2)

#查看0-1的比例,可以看出来,数据集基本上平衡
data['label'].value_counts()
1    9882
0    9788

#查看前10行的数据
data.head(10)
                         text  label
1703629526 Q 77544      1
5426                    葩葩葩l      0
14173            网站盘需要买的私聊我.      1
14582               买家秀和卖家秀?0
1730                  1776看v      0
1444              我又没送你谢我干啥ᚠ      0
10439            7645 555620
2448   伽韦 sx111505 珂视频箹   Ku      1
10423            影薇 w2753636      1
11782      胸还没有寒磊的 大ᚠ  还奶子疼!0

三、模型构建

from keras.preprocessing.text import Tokenizer
from keras.preprocessing.text import text_to_word_sequence
from keras.preprocessing.sequence import pad_sequences

from keras.models import Model 
from keras.models import Sequential

from keras.layers import Input, Dense, Embedding, Conv1D, Conv2D, MaxPooling1D, MaxPool2D
from keras.layers import Reshape, Flatten, Dropout, Concatenate
from keras.layers import SpatialDropout1D, concatenate
from keras.layers import GRU, Bidirectional, GlobalAveragePooling1D, GlobalMaxPooling1D

from keras.callbacks import Callback
from keras.optimizers import Adam

from keras.callbacks import ModelCheckpoint, EarlyStopping
from keras.models import load_model
from keras.utils.vis_utils import plot_model


#进行分字处理
import os
import pandas as pd
path  = '/Users/wuzhengxiang/Documents/DataSets/TextCnn'
os.chdir(path)
text_all = pd.read_csv('text_all.csv')

data = text_all
data['text'] = text_all['text'].apply(lambda x: ' '.join(x))
data.head()

x_train, x_test, y_train, y_test=\\
     train_test_split(data['text'], 
                      data['label'], 
                      test_size=0.2, 
                      random_state=42
                      )
print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)


x_train[45]
'\\ufeff + C 名 看 P , 是 威 哦 ❤   ❤'


MAX_NB_WORDS = 80000
tokenizer=Tokenizer(num_words=MAX_NB_WORDS)
tokenizer.fit_on_texts(x_train)


tokenizer.texts_to_sequences([x_train[38]])


train_sequences = tokenizer.texts_to_sequences(x_train)
test_sequences  = tokenizer.texts_to_sequences(x_test)


MAX_LENGTH = 35
padded_train_sequences = pad_sequences(train_sequences, maxlen=MAX_LENGTH)
padded_test_sequences  = pad_sequences(test_sequences,  maxlen=MAX_LENGTH)

padded_train_sequences
array([[  0,   0,   0, ...,   2,   8,   2],
       [  0,   0,   0, ..., 387, 443,  16],
       [  0,   0,   0, ...,  64,  59,  11],
       ...,
       [  0,   0,   0, ...,  27,  27,  27],
       [  0,   0,   0, ...,   3,   9,  71],
       [  0,   0,   0, ...,   1,  16,  16]], dtype=int32)
padded_train_sequences.shape
(15736, 35)

import numpy as np

def get_simple_rnn_model():
    embedding_dim = 300
    embedding_matrix = np.random.random((MAX_NB_WORDS, embedding_dim))
    inp = Input(shape=(MAX_LENGTH, ))
    x = Embedding(input_dim = MAX_NB_WORDS, 
                  output_dim = embedding_dim, 
                  input_length = MAX_LENGTH, 
                  weights=[embedding_matrix], trainable=True)(inp)
    x = SpatialDropout1D(0.3)(x)
    x = Bidirectional(GRU(100, return_sequences=True))(x)
    avg_pool = GlobalAveragePooling1D()(x)
    max_pool = GlobalMaxPooling1D()(x)
    conc = concatenate([avg_pool, max_pool])
    outp = Dense(1, activation="sigmoid")(conc)

    model = Model(inputs=inp, outputs=outp)
    model.compile(loss='binary_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])
    return model
rnn_simple_model = get_simple_rnn_model()

plot_model(rnn_simple_model, 
           #to_file='C:\\\\Users\\\\Desktop\\\\NLP任务实验\\\\rnn_simple_model.png', 
           show_shapes=True, 
           show_layer_names=True
          )


filepath="weights-improvement-epoch:02d-val_acc:.4f.hdf5"
checkpoint = ModelCheckpoint(filepath, 
                             monitor='val_acc', 
                             verbose=1, 
                             save_best_only=True,
                             mode='max'
                            )

batch_size = 256
epochs = 2
history = rnn_simple_model.fit(
                   x = padded_train_sequences, 
                   y = y_train, 
                   validation_data = (padded_test_sequences, y_test), 
                   batch_size = 256, 
                   #callbacks=[checkpoint], 
                   epochs = 5, 
                   verbose=1
           )

#best_rnn_simple_model = load_model('weights-improvement-01-0.8262.hdf5')

y_pred_rnn_simple = rnn_simple_model.predict(padded_test_sequences, 
                                                  verbose=1, batch_size=2048)

y_pred_rnn_simple = pd.DataFrame(y_pred_rnn_simple, columns=['prediction'])
y_pred_rnn_simple['prediction'] = y_pred_rnn_simple['prediction'].map(lambda p: 1 if p >= 0.5 else 0)

#y_pred_rnn_simple.to_csv('./predictions/y_pred_rnn_simple.csv', index=False)
#y_pred_rnn_simple = pd.read_csv('./predictions/y_pred_rnn_simple.csv')

print(accuracy_score(y_test, y_pred_rnn_simple))
0.9669547534316217

df = pd.DataFrame('text':x_test,'label':y_test,'pred':y_pred_rnn_simple)
df[df['label']!=df['pred']]

相比于第二个模型(拼音+ngram+逻辑回归)的0.95602,这个一下子就干到了0.9669,可以看到深度学习还是非常勇猛的,在序列领域,RNN有着不可取代的地位。后续我们继续考虑变异情况,再考虑用深度学习来试验,看看能做到多少的准确率。

四、模型解释

1)模型打印

plot_model 可以打印模型的框架,我们的框架如下,可以看到,使用了一个双项的GRU,然后进行了两种不同的池化方式进行池化在拼接起来。

2)模型训练过程

我们可以看看训练过程的损失下降和准确率上升,通过曲线,可以优化我们的训练过程。

import matplotlib.pyplot as plt# 画出损失函数曲线
plt.plot(history.history['loss'],    'bo',)
plt.plot(history.history['accuracy'], 'b',)
plt.title('train loss')plt.ylabel('acc')
plt.xlabel('epoch')plt.legend()# 画出损失函数曲线
plt.plot(history.history['val_loss'],    'bo',)
plt.plot(history.history['val_accuracy'], 'b',)
plt.title('val loss')
plt.ylabel('acc')
plt.xlabel('epoch')
plt.legend()

可以看到整个下降曲线还是很平滑的,如果我们轮数增加,准确率还有上升的可能性,大家可以测试下,有点非机器,一训练就开始发热了,

先写到这里了,大家可以看到,深度学习,对于解决语言问题,还是很有优势的,就这么简简单单的一段代码,准确率有了非常大的提升,后面的文章,我们继续深入研究各种风控识别算法。

以上是关于基于双向 GRU 的文本分类 Python 算法实战的主要内容,如果未能解决你的问题,请参考以下文章

NLP循环神经网络实现情感分类

3.5 tensorflow 中LSTM和GRU模块使用意境级讲解

《机器学习实战》基于朴素贝叶斯分类算法构建文本分类器的Python实现

笔记 基于双向多层次注意力网络的视觉文本情感分类

猿创征文丨深度学习基于双向LSTM模型完成文本分类任务

NLP-08textRNN