使用RNN进行中文文本分类(酒店评论)

首先导入必要的库

import numpy as np
import re
import jieba
import os

import matplotlib.pyplot as plt
%matplotlib inline

import tensorflow as tf
from tensorflow import keras

数据文件
https://pan.baidu.com/s/15_VGw2g3y6_q537USDuH3A
提取码: gb9k

查看下载的数据集
使用RNN进行中文文本分类(酒店评论)
我们把数据text 和label 放到两个数据集中

train_texts_orig = [] #放我们的文本评论text
train_target = [] #放我们的标签label

把positive_samples.txt和negative_samples.txt两个文件的内容导入到上面的数据集中

with open('positive_samples.txt', 'r', encoding='utf-8') as f:
    lines = f.readlines()
    for line in lines:
        #eval作用是使每行的line(str类型)转换为dict类型
        dic = eval(line)
        train_texts_orig.append(dic['text'])
        train_target.append(dic['label'])
        
with open('negative_samples.txt', 'r', encoding='utf-8') as f:
    lines = f.readlines()
    for line in lines:
        dic = eval(line)
        train_texts_orig.append(dic['text'])
        train_target.append(dic['label'])

其中正面评论2000条,负面评论2000条共计4000条数据

数据获取后,我们先要把中文的语句分解成单词,分词前我们先把标点去处

分词

#首先我们去掉每个样本的标点符后,然后用jieba分词

#jieba分词返回一个生成器,

#所以我们将分词结果转换成一个list,并将它索引化

#这样每一例评价的文本变成一段索引数字,对应着预训练词向量模型中的词。

数据预处理:用正则表达式去掉特殊符号,空格

word_all = set()
for text in train_texts_orig:
    text = re.sub("[\r|\n|\\s!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~“”?,!【】()、。:;’‘……¥·]+", "", text)


    #结巴分词进行分词
    cut = jieba.lcut(text)
    for word in cut:
        word_all.add(word)

我们把分好的词添加到word_all集合里,形成一个不重复的单词表格

len(word_all) #21829 这里我们得到21829个单词

使用RNN进行中文文本分类(酒店评论)
接下来我们来实现一个单词到id的word2id的映射

word2id = dict()
for i, word in enumerate(word_all):
    word2id[word] = i

查看结果

word2id

使用RNN进行中文文本分类(酒店评论)
这样我们就先实现了每个单词到id的实现,为我们后续把每个句子转换成数字的实现做好了准备,下面我们开始把文本中句子转换成相应的数字

train_x_all = []
for text in train_texts_orig:
    #用正则表达式去掉标点
    text = re.sub("[\r|\n|\\s!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~“”?,!【】()、。:;’‘……¥·]+", "", text)

    #结巴分词进行分词
    data = list()
    cut = jieba.lcut(text)
    for word in cut:
        index = word2id[word]
        data.append(index)
    train_x_all.append(data)

这样我们就把前面数据中的每句话转换成了相应的数字
查看一下文本转换成相应的数字

train_x_all[2]

使用RNN进行中文文本分类(酒店评论)
我们发现输入数据大小不一致,我们要保证每句话的长度一致

那个这个一致的长度设置多大好呢?下面我们来用直方图查看下文本中每句话长度的分布情况

#这里我们统计一下每个句子的长度,并形成一个列表
num_tokens = [ len(tokens) for tokens in train_x_all ]

下面我们用图形更加直观的显示一下

plt.hist(num_tokens, bins=50)
plt.ylabel('number of tokens')
plt.xlabel('length of tokens')
plt.title('Distribution of tokens length')
plt.show()

使用RNN进行中文文本分类(酒店评论)
发现长度大部分都在100以下,决定用85进行填充。

train_x_all = keras.preprocessing.sequence.pad_sequences(
    train_x_all,
    value=0,
    padding='post', #pre表示在句子前面填充,post表示在句子末尾填充
    maxlen=85
)

填充后文本长度不够的在末尾加0,长的就截断
查看填充和截断后的效果
train_x_all[1]
使用RNN进行中文文本分类(酒店评论)

前面是数据预处理部分,可以发现NLP当中数据预处理占很大的比重,这说明数据预处理的重要性。

下面我们对处理好的文本数据和标签数据进行整理,生成一个tf.data 并对数据进行shuffer

train_ds = tf.data.Dataset.from_tensor_slices(
    (train_x_all, train_target)).shuffle(20000).batch(32)

下面我们取一批数据查看一下数据是否shuffle了

example_input_batch, example_target_batch = next(iter(train_ds))
example_target_batch

使用RNN进行中文文本分类(酒店评论)

下面我们开始编写模型

这里我们要使用embedding层, 来训练我们文本的word2ver ,同时我们使用双向lstm

model = tf.keras.Sequential([
    tf.keras.layers.Embedding(len(word_all), 64),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])
model.summary()

使用RNN进行中文文本分类(酒店评论)
下面开始编译训练模型

model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
             optimizer=tf.keras.optimizers.Adam(1e-4),
             metrics=['accuracy'])

history = model.fit(train_ds, epochs=10)

使用RNN进行中文文本分类(酒店评论)
下面我进行模型验证

这里我们定义一个方法,用来对输入的语句进行判断

def predict_sentiment(text):
    print(text)
    text = re.sub("[\r|\n|\\s!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~“”?,!【】()、。:;’‘……¥·]+", "", text)

    cut = jieba.lcut(text)
    cut_list = []
    for word in cut:
        index = word2id[word]
        cut_list.append(index)

    #padding
    tokens_pad = keras.preprocessing.sequence.pad_sequences(
        [cut_list],
        value=0,
        padding='post', #pre表示在句子前面填充,post表示在句子末尾填充
        maxlen=85)

    #预测
    result = model.predict(tokens_pad)
    print(result)
    coef = result[0][0]
    if coef > 0.5:
        print('是一例正面评价','output=%.2f'%coef)
    else:
        print('是一例负面评价','output=%.2f'%coef)   

下面我们建立一些评论文本,来看看模型效果,

第一个评论我复制的训练数据中的正文本,第二个我复制训练的数据中的负文本

其它数据是自编的评论

test_list = [
    '早餐太差,无论去多少人,那边也不加食品的。酒店应该重视一下这个问题了。\n\n房间本身很好。',
    '标准间太差 房间还不如3星的 而且设施非常陈旧.建议酒店把老的标准间从新改善.'
    '酒店设施不是新的,服务态度很不好',
    '酒店卫生条件非常不好',
    '床铺非常舒适',
    '房间很凉,不给开暖气',
    '房间很凉爽,空调冷气很足',
    '酒店环境不好,住宿体验很不好',
    '房间隔音不到位' ,
    '晚上回来发现没有打扫卫生',
    '因为过节所以要我临时加钱,价格贵',
    '房间宽敞,床铺干净,卫生很好,有早餐,价格不贵',
]
for text in test_list:
    predict_sentiment(text)

测试结果整体看还可以,但有些评论还是判断不是很好,这跟我们的数据有管。向第一个评论,说早餐太差,还定义为正面评论。
使用RNN进行中文文本分类(酒店评论)

上一篇:Linux中对文本分组统计排序


下一篇:最小割集