keras的LSTM文本分类预处理及代码简单实现

      + python技术交流群,一起学习:819345479

最近公司在做文本分类处理这一块,自己也没接触,过于是在茫茫的博客中苦苦寻找,给大家推荐一篇比较不错的实在github上找到的,网址贴上。这篇文章的代码实现还是比较简单的。但是存在两个问题:一是训练集。这个训练集是直接从这个包中直接加载并训练的,对于实际的应用来说做文本的类的人士需要将自己的训练集和测试集替换掉它。二是自动分类的预处理过程。它没有介绍在训练之前数据的预处理以及数据的卷积化(应该是这样说,也就是将数据经过切分、去重、排序(可选)等操作后转化为一串对应类别的序列。不论是处理成one-hot还是word-embidding)。所以这篇文章我会介绍一下数据预处理的过程,而后面循环训练的部分具体各函数的具体功能以及运算方法我还没深入了解,就不在大家面前献丑了。还有就小编如果哪里有不正确或者不合适的地方请不吝指正或者联系小编进行修改。(qq:1549990441    加时请详细备注,谢谢!)

小编自己理解的文本分类的基本过程:分类-->根据训练模型构建数据的shape-->训练-->结果保存

详解如下:

1、分类:

这一块的话小编在实现的时候是手动分类的,因为公司最近项目在游戏方面,所以分类的层级结构大致是这样的:

2、分好类之后开始构建所需要的shape。数据shape格式如下:

这里小编要提醒一下:1表示这篇文章属于该类别,0表示不属于,可以存在全为1的一行,即一篇文章对应对多个类别,但是不能出现全为0的情况,因为这样训练没意义。所以在构建shape是需要对全为0的进行剔除,小编后面的代码中也会实现。并且在构建shape的时候需要每一篇文章与shape对应。我是如上图这样理解的:行代表每一篇文章,列代表你锁分的类别,而在最后训练的结果中中也是这样的shape,三十数据却变成了0--1之间的一个数,即预测值,哪一列 接近于1说明越接近哪一个类别。

3、shape构建完之后开始构建模型。有两种方法:一是向layer添加list的方式,二是通过.add()方式一层层添加,一个add为一层。小编制这里用的是 .add()方法。

model = Sequential()
model.add(Dense(25, input_dim=784))        # 这里的25需要与你构建的shape对应

model.add(Activation('relu'))

每一个函数里面的参数小编在这里就不一一介绍了,详细见keras文档中文文档

4、模型构建完开始编译。设置优化器,损失函数,评估模型的指标等,一般默认就可以,后期优化可以在详细修改。

model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])

5、模型训练。其他参数需要在添加修改。

fit(self, x_train,  y_train,  batch_size=32, 

        validation_data=(x_test, y_test))

fit函数返回一个History的对象,其History.history属性记录了损失函数和其他指标的数值随epoch变化的情况,如果有验证集的话,也包含了验证集的这些指标变化情况。

x_train:输入训练数据。模型只有一个输入时x的类型是numpy array,模型多个输入时x的类型应当为list,list的元素是对应于各个输入的numpy array

# y_train:标签,numpy array

# batch_size:指定进行梯度下降时每个batch包含的样本数。

# validation_data:形式为(X,y)的tuple,是指定的验证集。此参数将覆盖validation_spilt。

5、测试、预测数据。

evaluate(self, x_test, y_test, batch_size=32, verbose=1)

#本函数按batch计算在某些输入数据上模型的误差,其参数有:

#x_test:输入数据,与fit一样,是numpy array或numpy array的list

#y_test:标签,numpy array

#batch_size:整数,含义同fit的同名参数

#verbose:含义同fit的同名参数,但只能取0或1

predict_proba(self, x_test, batch_size=32, verbose=1)

本函数按batch产生输入数据属于各个类别的概率,函数的返回值是类别概率的numpy array

6、训练测试数据和结果保存。

np.savetxt("x_train.txt", x_train)

np.savetxt("x_test.txt", x_test)

np.savetxt("y_train.txt", list14)

np.savetxt("y_test.txt", test_type_list)

open('my_model.json', 'w').write(model_json)

model.save_weights('my_model_weights.h5')

代码:

#! python3

# coding=utf-8

from __future__ import print_function

import numpy as np

from keras.preprocessing import sequence

from keras.models import Sequential

from keras.layers import Dense, Embedding

from keras.layers import LSTM

import pymysql

import jieba

from bs4 import BeautifulSoup

import re

from keras.models import model_from_json

import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

# max_features = 20000

maxlen = 80  # cut texts after this number of words (among top max_features most common words)

batch_size = 32

print('0 ---> Loading data...')

type = ['游戏活动资讯', '游戏直播资讯', '赛事资讯', '赛事解读', '赛事采访', '赛事回顾', '赛事竞猜、博彩', '版本、服务更新','游戏攻略', '游戏教学', '战队动态', '人物采访', '人物群访', '电竞主播', '电竞选手', '娱乐八卦', '业界新闻, 电子竞技体育','产业报告', '电竞发展趋势', '电竞立法', '人工智能电竞', '电竞峰会', '电竞奥运', '颁奖盛典', '电竞协会']

list13 = []     # 存放序列全为0的原始list [0, 0, 0, ....]

list14 = []     # 存放 每一篇文章类别 的list,[[], [], [], ....]

article_list = []   # 存放每一篇符合要求的文章

tag_list = []   # 存放每一篇文章的标签

word_dict = []  # 词字典

db = pymysql.connect("xxxxxxx", "xxxx", "xxxx", "xxxx")

db.set_charset("utf8")

cursor = db.cursor()

sql = "select tag,title,main from bas_knowledge_info where tag like'%电子竞技%'"

cursor.execute(sql)

db.commit()

results1 = cursor.fetchall()

# 存放每一个类别的  类别序列

list1_type1 = []

list1_type2 = []

......

list1_type25 = []

# 结巴分词函数,返回分词后的一个列表

def word_split(text):

word_list = []

word_primitive = jieba.cut(text, cut_all=False)

for word in word_primitive:

if len(word) > 0:

word_list.append(word)

return word_list

# 读取停用词表,放在list里面

def stopwords():

stopwords_list = []

f = open('stopwords.txt', 'r', encoding="utf-8")

all_sw = f.read()

stop_num = all_sw.split('\n')

for each in stop_num:

stopwords_list.append(each)

return stopwords_list

# 停用词的一个列表

stopwords_list = stopwords()

print("文本长度是:", len(results1))

for i in range(0, len(results1)):

for j in range(0, 25):

list13.append(0)

# 1 游戏活动资讯

if str(results1[i][0]).__contains__('活动'):

if len(list1_type1) <= 800:     # 这里的list1_type1只起到一个判断的作用,用于减少训练的样本数

list13[0] = 1

list1_type1.append(0)

......

# 25 电竞协会:

if str(results1[i][0]).__contains__('协会'):

if len(list1_type25) <= 800:

list13[24] = 1

list1_type25.append(0)

# 去掉list13里面全部为0的list

if 1 in list13:

try:

list14.append(list13)

# 将所遇标题和正文拼接在一块,构建训练文章list

title = re.sub('\s', '', str(BeautifulSoup(results1[i][1]).text))

main = re.sub('\s', '', str(BeautifulSoup(results1[i][2]).text))

all1 = str(title) + str(main)

article_list.append(all1)       # article_list和list14的长度一致,在后面选取测试集的时候会用到

tag_list.append(results1[i][0])

except Exception:

pass

else:

pass

try:

# 将所遇标题和正文拼接在一块,并且将所有的文本标题拼接成一个大的str,用于构建word_dict

title1 = re.sub('\s', '', str(BeautifulSoup(results1[i][1]).text))

main1 = re.sub('\s', '', str(BeautifulSoup(results1[i][2]).text))

all2 = str(title1) + str(main1)

# 这里构建word_dict,避免内存不足的问题,但是运行会慢

wd_article_word_list = word_split(all2)   # 切分

wd_article_word_list = list(set(wd_article_word_list))  # 去重

for d in wd_article_word_list:

if d not in word_dict:

word_dict.append(d)

else:

pass

except Exception:

pass

list13 = []

print("1 ---> 所有文章str,文章list,文章tag已经完成")

# 文章词dict已经保存成文件

with open('word_dict1.txt', 'w', encoding='utf-8', errors='ignore') as f:

for each6 in range(0, len(word_dict)):

f.write(str(word_dict[each6]))

if each6 < len(word_dict)-1:

f.write('\n')

else:

pass

print("2 ---> 文章词dict已经保存成文件")

# print("--->去掉停用词和去重之后的词的字典是:", word_dict)

# 每一篇文章的分词,最后放在一个大的列表里面

txt_word_dict = []  # 文章的词字典

article_word_index = []  # 存放每一篇文章的索引(序列)

all_article_word_index = []  # 存放所有文章的索引(序列)

for each2 in article_list:

txt_word_list = word_split(each2)   # 每一篇文章切分之后的list

for each3 in txt_word_list:

if each3 in stopwords_list:

pass

else:

txt_word_dict.append(each3)

txt_word_dict = list(set(txt_word_dict))  # 去重

# 根据word_dict将文章的词映射成索引

for each4 in txt_word_dict:

index = word_dict.index(each4)      # 直接找到下标

# 将下表存入文章list中

article_word_index.append(index)

print("====>", article_word_index)

all_article_word_index.append(article_word_index)

article_word_index = []

txt_word_dict = []

print("3 ---> 所有文章的每一篇已经根据word_dict完成了映射")

# 选出一部分作为测试集

num = 1

test_type_list = []     # 用测测试的类别序列[[1, 0, 0, ...], [0, 0, 1, ...], ....]

test_article_wordindex_list = []    

# 用于测试的文章序列[[15, 165, ...], [254, 1565, ...], ....]

test_article111 = []       # 文章文本,用于导入数据库看训练结果

tag_list1 = []      # 文章的标签,用于导入数据库看训练结果

while num < len(list14):

test_type_list.append(list14[num])

test_article_wordindex_list.append(all_article_word_index[num])

test_article111.append(article_list[num])

tag_list1.append(tag_list[num])

num += 2

print("4 ---> 训练集已经抽取完成")

print(len(all_article_word_index), 'train sequences')

print(len(test_article_wordindex_list), 'test sequences')

print('Pad sequences (samples x time)')

x_train = sequence.pad_sequences(all_article_word_index, maxlen=maxlen)

x_test = sequence.pad_sequences(test_article_wordindex_list, maxlen=maxlen)

print('x_train shape:', x_train.shape)

print('x_test shape:', x_test.shape)

# 保存,便后后面对模型类别的增删改(这里要注意savetxt这个函数保存为txt文件是多维数组的长度要一致)

np.savetxt("x_train.txt", x_train)

np.savetxt("x_test.txt", x_test)

np.savetxt("y_train.txt", list14)

np.savetxt("y_test.txt", test_type_list)

print('Build model...')

model = Sequential()

model.add(Embedding(len(word_dict), 128))

model.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2))

model.add(Dense(25, activation='sigmoid'))

model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])

print('5 ---> 编译结束,开始Train...')

model.fit(x_train, np.array(list14),batch_size=batch_size,epochs=15,

  validation_data=(x_test, np.array(test_type_list)))

score, acc = model.evaluate(x_test, np.array(test_type_list),batch_size=batch_size)

# print('Test score:', score)

# print('Test accuracy:', acc)

tag2 = ''

print("6 ---> 开始预测")

a = model.predict_proba(x_test, batch_size=batch_size, verbose=1)

# 保存网络结构,载入网络结构

model_json = model.to_json()

open('my_model.json', 'w').write(model_json)

model.save_weights('my_model_weights.h5')

print("7 ---> 保存权重完成")

# 加载模型

# model = model_from_json(open('my_model_architecture.json').read())

# model.load_weights('my_model_weights.h5')

for each7 in range(0, len(a)):

for each8 in range(0, len(a[each7])):

if float(a[each7][each8]) >= 0.6:

tag2 = tag2 + type[each8] + ','

else:

pass

ins_test_sql = "insert

into bas_knowledge_info_type(org_classification,new_classification,main) " \

"values('"+str(result[each7][0])+"','"+str(tag_list1[each7])+"'," \

   "'"+str(test_article111[each7])+"')"

cursor.execute(ins_test_sql)

db.commit()

tag2 = ''

print("8 ---> 测试数据已经存入数据库")

猜你喜欢

转载自blog.csdn.net/genius_man/article/details/79514270