版权所有,转载请注明出处
英文文本分类代码实战
制作自己的文本数据集
数据文本清洗
在 datapretreat_1.py文件中进行初步的文件清洗。
1、读取训练集文件下的所有文件内容
2、将文本标签 [a、b、c、d、e] 分别用数字 [0、1、2、3、4] 表示
3、只读取英文字符,忽略数字、标点
4、以单个文件及该文件所属标签作为一条数据(每个文件表示数据集中的一条数据)
5、将一条数据中割裂的文本单词组合成一个字符串(形成初步清洗好的字符串文本)
6、使用 numpy 中的 np.savez() 函数保存文件,文件名为: train_dataset.npz 和 test_dataset.npz 文件
文本数据存放方式
文本数据存放方式如下图所示
文本清洗代码
'''
created by Yang in 2020.11.1
'''
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers , Sequential , metrics , losses , optimizers
import nltk
from nltk import word_tokenize , pos_tag
from nltk.stem import WordNetLemmatizer
from nltk.corpus import stopwords
from nltk import FreqDist
import matplotlib.pyplot as plt
from wordcloud import WordCloud
from imageio import imread
import sys
import os
import csv
import re
from collections import defaultdict
from gensim.corpora import Dictionary
import string
import numpy as np
'''
数据集预处理:
分词--词性标注--词形归一化--去除停用词--去除特殊字符--单词大小写转换-(文本分析)
'''
#文本预处理函数
def text_pretreat(text):
"""
对读取的文本数据进行清洗,并返回
"""
#分词
token_words = word_tokenize(text)
#词性标注
token_words = pos_tag(token_words)
#词形归一化(指明单词词性)
words_lematizer = []
wordnet_lematizer = WordNetLemmatizer()
for word, tag in token_words:
if tag.startswith('NN'):
word_lematizer = wordnet_lematizer.lemmatize(word, pos='n') # n代表名词
elif tag.startswith('VB'):
word_lematizer = wordnet_lematizer.lemmatize(word, pos='v') # v代表动词
elif tag.startswith('JJ'):
word_lematizer = wordnet_lematizer.lemmatize(word, pos='a') # a代表形容词
elif tag.startswith('R'):
word_lematizer = wordnet_lematizer.lemmatize(word, pos='r') # r代表代词
else:
word_lematizer = wordnet_lematizer.lemmatize(word)
words_lematizer.append(word_lematizer)
#去除停用词
cleaned_words = [word for word in words_lematizer if word not in stopwords.words('english')]
words_list = [word for word in cleaned_words if word not in string.punctuation]
#大小写转化
words_lists = [x.lower() for x in words_list ]
return words_lists
def text_show(words_lists):
"""
文本分析
"""
freq = FreqDist(words_lists)
for key,val in freq.items():
print (str(key) + ':' + str(val))
#可视化折线图
freq.plot(20,cumulative=False)
#可视化词云
words = ' '.join(words_lists)
wc = WordCloud().generate(words)
plt.imshow(wc,interpolation='bilinear')
plt.axis("off")
plt.show()
'''
文件处理:
读取文件,语料清洗,另存语料文件
'''
#文件读取函数
def readfile(file_path):
fp = open(file_path , mode='r' , encoding='UTF-8' )
content = fp.read()
fp.close()
return content
#语料文件夹清洗
def clean_save(read_path , save_name):
dic = {'C':0 , 'E':1 , 'R':2 , 'T':3 , 'V':4}
#初步清洗训练集文本内容放在一个文件,做词频处理
texts_infile=[]
#暂时存放所有数据
tmp_all_contents = []
#存放所有数据
texts=[]
laybels = []
#获取读取文件路径下的所有文件目录
seg_dirs = os.listdir(read_path)
for dir in seg_dirs:
#获取子目录完整路径
seg_dirpath = read_path + "/"+dir + "/"
#获取子目录下所有文件
files_list = os.listdir(seg_dirpath)
#遍历子目录所有文件
for file in files_list:
#获取文件完整目录
file_path = seg_dirpath +"/"+ file
#单个文本数据
text_dataset = []
#获取文件内容
content = readfile(file_path).strip()
#获取英文文本数据
content = re.sub(r'[^a-zA-Z]'," ",content)
#删除换行与多余空格
content = content.replace("\r\n" , " ").strip()
#文本处理
content = text_pretreat(content)
texts_infile +=content
#结果展示
# text_show(content)
#追加子目录文件内容并添加标签
tmp_data= list(content)
tmp_laybel = dic[dir]
text_dataset.append(tmp_data)
text_dataset.append(tmp_laybel)
tmp_all_contents.append(text_dataset)
#统计所有训练集数据词频
frequency = defaultdict(int)
for word in texts_infile:
frequency[word] += 1
#删除只出现一次的单词
for text in tmp_all_contents:
data = [w for w in text[0] if frequency[w] >1 and len(w) > 1 ]
string_data = " ".join(str(i) for i in data)
label = text[1]
texts.append(string_data)
laybels.append(label)
np.savez(save_name , x = texts , y = laybels)
#主函数
if __name__ == "__main__":
#训练集读取路径
traindataset_path = "F:/code/tfcode/school_code/train/"
#测试集读取路径
testdataset_path = "F:/code/tfcode/school_code/test/"
#训练集清洗
clean_save(traindataset_path , save_name='train_dataset' )
clean_save(testdataset_path , save_name='test_dataset')
文本数据结构
结构类似下图,文本存放类型是 .npz方式,无法直接打开查看,但是适合代码读取。
数据文本向量化(词嵌入方法)
1、读取清洗好的 train_dataset.npz 和 test_dataset.npz 文件
2、获取训练集文本词袋大小
3、获取最大文本文件的大小
4、将所有文本数据以词袋中唯一的编号表示
5、以最大文本文件大小作为基准,文本数据小于最大文本文件大小的填充至该大小
6、使用 numpy 中的 np.savez() 函数保存文件,文件名为: train_data_vec.npz 和 test_data_vec.npz 文件
数据向量化代码
'''
created by Yang in 2020.11.1
'''
import numpy as np
from keras_preprocessing.text import Tokenizer
import re
from keras_preprocessing.sequence import pad_sequences
#读取数据集函数
def get_dataset(dataset_path):
npzfile = np.load(dataset_path)
return npzfile['x'] , npzfile['y']
#计算最大文本长度
def get_maxlen(train_texts , test_texts):
maxlen = 0
for text in train_texts:
text = re.findall(r'\b\w+\b' , text)
if len(text) > maxlen:
maxlen = len(text)
for text in test_texts:
text = re.findall(r'\b\w+\b' , text)
if len(text) > maxlen:
maxlen = len(text)
return maxlen
#文本转换为向量并填充
def texts2vec_padding(train_texts , test_texts ,maxlen):
tokenizer = Tokenizer(num_words=10604)
tokenizer.fit_on_texts(train_texts)
texts_train = tokenizer.texts_to_sequences(train_texts)
texts_test = tokenizer.texts_to_sequences(test_texts)
#填充
texts_train = pad_sequences(texts_train , padding='post' , maxlen=maxlen)
texts_test = pad_sequences(texts_test , padding='post' , maxlen=maxlen)
vocab_size = len(tokenizer.word_index)+1
return texts_train , texts_test , vocab_size
train_dataset_path = 'F:/code/tfcode/school_code/dataclean_code/train_dataset.npz'
test_dataset_path = 'F:/code/tfcode/school_code/dataclean_code/test_dataset.npz'
#训练集文本与标签
train_x , train_y = get_dataset(train_dataset_path)
test_x , test_y = get_dataset(test_dataset_path)
#获取最大文本长度
maxlen = get_maxlen(train_x , test_x)
train_x , test_x , vocab_size = texts2vec_padding(train_x , test_x , maxlen)
np.savez('train_data_vec' , x=train_x , y=train_y)
np.savez('test_data_vec' , x=test_x , y=test_y)
向量化结果
END
以上把文本数据清洗完成,并转换成数值类型。文本中的单词以训练集中的词袋中的唯一数字表示。原理通用,清洗策略不同需稍微修改。将数据集改成自己的数据集,存放路径修改即可。
模型训练
1、读取处理好的训练集与测试集 train_data_vec.npz 和 test_data_vec.npz 文件
2、将测试集与训练集进行切分与打乱
3、构建basic_model模型(基础全连接网络模型)、LSTM_model模型(基础lstm模型)、CNN_model(基础一维卷积神经网络模型)
4、训练与测试,计算平均准确率与loss
5、绘制图像
测试代码
'''
created by Yang in 2020.11.1
'''
import numpy as np
import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras import layers , Sequential , datasets , optimizers,losses
from tensorflow.keras.layers import LSTM
import matplotlib.pyplot as plt
import random
#读取数据集函数
def get_dataset(dataset_path):
npzfile = np.load(dataset_path)
return npzfile['x'] , npzfile['y']
#画图函数
def draw(epoch_sumloss , epoch_acc):
x=[i for i in range(len(epoch_sumloss))]
#左纵坐标
fig , ax1 = plt.subplots()
color = 'red'
ax1.set_xlabel('epoch')
ax1.set_ylabel('loss' , color=color)
ax1.plot(x , epoch_sumloss , color=color)
ax1.tick_params(axis='y', labelcolor= color)
ax2=ax1.twinx()
color1='blue'
ax2.set_ylabel('acc',color=color1)
ax2.plot(x , epoch_acc , color=color1)
ax2.tick_params(axis='y' , labelcolor=color1)
fig.tight_layout()
plt.show()
if __name__ == "__main__":
#读取路径
train_path = 'F:/code/tfcode/school_code/dataclean_code/train_data_vec.npz'
test_path = 'F:/code/tfcode/school_code/dataclean_code/test_data_vec.npz'
#读取训练集与测试集
train_x , train_y = get_dataset(train_path)
test_x , test_y = get_dataset(test_path)
seed = 1234
random.seed(seed)
random.shuffle(train_x )
random.seed(seed)
random.shuffle(train_y)
seed = 2143
random.seed(seed)
random.shuffle(test_x )
random.seed(seed)
random.shuffle(test_y)
train_y = tf.one_hot(train_y , depth = 5)
test_y = tf.one_hot(test_y , depth=5)
#数据集词袋大小
vocab_size =10604
#最长文本
max_textlen = 384
#词向量大小
embedding_dim =50
#创建文本分类基础模型
basic_model = Sequential([
layers.Embedding(input_dim=vocab_size ,
output_dim=embedding_dim,
input_length=max_textlen),
layers.Flatten(),
# layers.BatchNormalization(),
layers.Dense(50,activation='relu'),
# layers.BatchNormalization(),
layers.Dense(25,activation='relu') ,
# layers.BatchNormalization() ,
layers.Dense(5,activation='sigmoid') ,
])
#lstm模型
lstm_model = Sequential([
layers.Embedding(input_dim=vocab_size,
output_dim=embedding_dim,
input_length=max_textlen),
LSTM(128 , return_sequences=False),
layers.BatchNormalization() ,
# layers.Dense(256 ,activation='relu'),
# layers.Dense(128 ,activation='relu'),
layers.Dense(16 ,activation='relu'),
# layers.BatchNormalization(),
layers.Dense(5,activation='relu')
])
#CNN模型
CNN_model = Sequential([
layers.Embedding(input_dim=vocab_size,
output_dim=embedding_dim,
input_length=max_textlen),
layers.Conv1D(512 ,5, activation='relu'),
layers.GlobalMaxPooling1D(),
layers.Dense(64 , activation='relu'),
layers.BatchNormalization(),
layers.Dense(32 , activation='relu'),
layers.Dense(5 , activation='relu')
])
CNN_model.compile(optimizer='adam',loss='binary_crossentropy' , metrics=['accuracy'])
CNN_model.summary()
history = CNN_model.fit(train_x , train_y , epochs=100 , verbose=False , validation_data=(test_x , test_y),batch_size=128)
loss , acc =CNN_model.evaluate(train_x , train_y , verbose=False)
loss , acc =CNN_model.evaluate(test_x , test_y , verbose=False)
draw(history.history['loss'] , history.history['accuracy'])
结果
全连接模型
lstm模型
卷积模型
总结
文本分类中文本的清洗对最后结果有些影响。