目录
一、数据集
分为两个excel, 分别含有积极和消极的文本,链接。完整代码最下方。
链接:https://pan.baidu.com/s/1IvqNIL-YHUjTlJRc-Asv9w?pwd=5e94
提取码:5e94
二、数据预处理
1.jieba分词
#合并语料
data_sum = pd.concat([word_pos,word_neg],ignore_index=True)
#计算语料数目
word_neglen = len(word_neg) #10428
word_poslen = len(word_pos) #10677
#定义分词函数, jieba默认为精确模式,若设置全模式,需在cut中添加参数cut_all=True
def1 = lambda x: list(jieba.cut(x))
#应用函数将文本进行分割,保存到data_sum['words']
data_sum['words'] = data_sum[0].apply(def1)
结果如下
2.tokenizer转序列
首先将words列的每一行由逗号分割改为空格分割,类比英文中的空格分割,便于使用tokenizer转序列。(分割后的逗号是原来文本自带的)
texts = [' '.join(x) for x in pn['words']]
#print(texts[0])
#'做 父母 一定 要 有 刘墉 这样 的 心态 , 不断 地 学习 , 不断 地 进步 , 不断 地 给 自己 补充
再构建分词器tokenizer,一般texts_to_sequences与pad_sequences结合使用,可以将处理后的文本序列转换为等长的数字序列。
# 实例化分词器,设置字典中最大词汇数为30000
tokenizer1 = Tokenizer(num_words=30000)
# 传入我们的训练数据,建立词典
tokenizer1.fit_on_texts(texts)
# 把词转换为编号(索引序列),词的编号根据词频设定,频率越大,编号越小
sequences = tokenizer1.texts_to_sequences(texts)
# 把序列设定为1000的长度,超过1000的部分舍弃,不到1000则补0
#pad_sequence 序列转化为长度相同的新序列 padding:补0,post是在结尾补
sequences = pad_sequences(sequences, maxlen=1000, padding='post')
sequences = np.array(sequences)
结果:
这里通过查看字典测试一下,文本与序号是否对应, 用了第一句话第一个词“做”来测试,可以看到与上图数组的第一个元素相对应。
# 词对应编号的字典 tokenizer.word_index:查看单词索引
dict_text = tokenizer1.word_index
print(dict_text['做']) #130
3.打乱数据,划分训练集和测试集。这里将标签值区分,积极:[0,1] 消极:[1,0], 最后通过1的索引位置来判断积极或消极(积极中1的索引为1, 消极的1索引为0)。
# 定义标签
positive_labels = [[0, 1] for i in range(poslen)]
negative_labels = [[1, 0] for i in range(neglen)]
y = np.concatenate([positive_labels, negative_labels])
# 打乱数据
np.random.seed(10) #permutation:随机排列序列
shuffle_indices = np.random.permutation(np.arange(len(y)))
#
x_shuffled = sequences[shuffle_indices]
y_shuffled = y[shuffle_indices]
# 数据集切分为两部分
#划分
test_sample_index = -1 * int(0.1 * float(len(y)))
x_train, x_test = x_shuffled[:test_sample_index], x_shuffled[test_sample_index:]
y_train, y_test = y_shuffled[:test_sample_index], y_shuffled[test_sample_index:]
打乱后的x与y
三、集成CNN+LSTM模型构建
sequence_input = Input(shape=(1000,))
# Embedding层,30000表示30000个词,每个词对应的向量为128维,序列长度为1000
embedding_layer = Embedding(30000,
128,
input_length=1000)
embedded_sequences = embedding_layer(sequence_input)
lstm1 = LSTM(128,return_sequences=True,dropout=0.2, recurrent_dropout=0.2)(embedded_sequences)
lstm1 = LSTM(64,return_sequences=True,dropout=0.2, recurrent_dropout=0.2)(lstm1)
lstm1 = Conv1D(filters=32, kernel_size=3, activation='relu')(lstm1)
lstm1 = MaxPooling1D(pool_size=2)(lstm1)
lstm1 = Conv1D(filters=32, kernel_size=3, activation='relu')(lstm1)
lstm1 = MaxPooling1D(pool_size=2)(lstm1)
lstm1 = Flatten()(lstm1)
lstm1 = Dense(16, activation='relu')(lstm1)
lstm1 = Dropout(0.5)(lstm1)
preds = Dense(2, activation='softmax')(lstm1)
# 定义模型
model = Model(sequence_input, preds)
model.summary()
训练:
# 训练模型 使用交叉熵损失函数, adam优化器
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['acc'])
#
model.fit(x_train, y_train,
batch_size=128,
epochs=5,
validation_data=(x_test, y_test))
准确率:
四、预测
这里使用try-except,目的在于如果输入的文本中有词不在原先字典中,则返回0,不让它影响结果。 np.argmax返回的是最大值也就是[0,1]中1的索引,积极[0,1] 消极[1,0] 若result为1,则为积极。
参考链接:(保姆级教程)【Keras入门到实战600集一次性讲清楚】清华教程强烈推荐的Keras教程!带你一周搞定!——_哔哩哔哩_bilibili