首先导入必要的库
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
查看下载的数据集
我们把数据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个单词
接下来我们来实现一个单词到id的word2id的映射
word2id = dict()
for i, word in enumerate(word_all):
word2id[word] = i
查看结果
word2id
这样我们就先实现了每个单词到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]
我们发现输入数据大小不一致,我们要保证每句话的长度一致
那个这个一致的长度设置多大好呢?下面我们来用直方图查看下文本中每句话长度的分布情况
#这里我们统计一下每个句子的长度,并形成一个列表
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()
发现长度大部分都在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]
前面是数据预处理部分,可以发现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
下面我们开始编写模型
这里我们要使用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()
下面开始编译训练模型
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)
下面我进行模型验证
这里我们定义一个方法,用来对输入的语句进行判断
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)
测试结果整体看还可以,但有些评论还是判断不是很好,这跟我们的数据有管。向第一个评论,说早餐太差,还定义为正面评论。