Python实现对中文文本的分类处理+源码

本人是自然语言处理方向研究生一枚,最近在尝试用当下比较火热的一些算法来进行文本的处理。
本程序实现的是对《计算机网络》领域本体的题目进行分类,因此数据集需要自己构建,当然了,网上也有很多开源的数据集,比如中文的10类语料集,可以去我的百度云下载:链接:https://pan.baidu.com/s/1sDn4pBmWSgy87C_mRUX5_g
提取码:wuqe

废话不多说,直接附上源码,供大家一起交流

# _*_ coding:utf-8 _*_
# 开发人员 : lenovo
#开发时间 :2019/12/2617:55
# 文件名称 :Chinese Classification.py
# 开发工具 : PyCharm

#代码参考网址:https://blog.csdn.net/weixin_42608414/article/details/89856566
#实现的通过LSTM模型,实现10分类,并且预测其效果
#数据集总大小62775,按照cat,label,review格式存放。其中书籍类共有


#coding=utf-8
import  pandas as pd
import  datetime
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense, Embedding, LSTM,SpatialDropout1D
from sklearn.model_selection import train_test_split
from keras.utils.np_utils import to_categorical
from keras.callbacks import EarlyStopping
from keras.layers import Dropout
import jieba as jb
import re




Start = datetime.datetime.now()
print("开始运行的时间是:",Start)

# df = pd.read_csv('./data/online_shopping_10_cats.csv')
#df =pd.read_csv('D:\PyCharm\PyCharmWorkPlace\WorkPlace1\TextClassification\data\online_shopping_10_cats.csv')
df =pd.read_csv('D:\PyCharm\PyCharmWorkPlace\WorkPlace1\TextClassification\data\MyData.csv')

# 我们的数据有两个字段,其中cat字段表示类别,review表示用户的评价信息,数据总量为62774,且评价内容全部为中文
df = df[['cat','review']]

#  ******************************************
print("数据总量是:%d" %len(df))   # 数据总量是:62774
# print("数据总量是:",df)  #

print(df.sample(10))  #随机的选择10个例子出来,种类也是随机

#  ******************************************
print("在cat列中共有%d个空置" %df['cat'].isnull().sum())    # 在cat列中共有0个空置
print("在review列中共有%d个空值"%df['review'].isnull().sum())  #在review列中共有1个空值
df[df.isnull().values==True]
df = df[pd.notnull(df['review'])]

#  ******************************************
d = {'cat':df['cat'].value_counts().index,'count':df['cat'].value_counts()}
df_cat = pd.DataFrame(data=d).reset_index(drop=True)
print("df_cat的结果是 \n ",df_cat)


#  *******************用图形化的方式查看一下各个类别的分布***********************
df_cat.plot(x='cat',y='count',kind = 'bar',legend = False, figsize=(8,5)) #figsize(a,b) 设置图形的大小,a 为图形的宽, b 为图形的高,单位为英寸
plt.title("类目分布")
plt.ylabel('数量',fontsize = 18)
plt.xlabel('类目',fontsize = 18)
#plt.text(0.5,0,'类目')  #Text(0.5,0,'类目') ,原来的Text()函数应该是jupyter版本的,运行不出来,更改为现在运行的函数即可
plt.savefig('Picture1')
plt.show()


#   ************数据预处理*****************
#将cat类转换成id,这样便于以后的分类模型的训练
#对应Id关系为 书籍:0,平板:1,手机:2,水果:3,洗发水:4,热水器:5,蒙牛:6,衣服:7,计算机 :8,酒店:9

df['cat_id'] = df['cat'].factorize()[0]  #将对象编码为枚举类型或类别变量。factorize函数可以将Series中的标称型数据映射称为一组数字,相同的标称型映射为相同的数字。
#返回值:factorize函数的返回值是一个tuple(元组),元组中包含两个元素。第一个元素是一个array,其中的元素是标称型元素映射为的数字;第二个元素是Index类型,其中的元素是所有标称型元素,没有重复。

cat_id_df = df[['cat','cat_id']].drop_duplicates().sort_values('cat_id').reset_index(drop=True)
cat_to_id = dict(cat_id_df.values)
id_to_cat = dict(cat_id_df[['cat_id','cat']].values)
df.sample()  #df.sample() 如果()中没有值,则默认输出一个例子
print(df.sample(1))
#print("数据预处理结果为:",df.sample(18)) # 随机输出18个例子
print("cat_id_df是:",cat_id_df) # 输出对应的cat和cat_id
print("cat_to_id是:",cat_to_id) #结果为:'书籍': 0, '平板': 1, '手机': 2, '水果': 3, '洗发水': 4, '热水器': 5, '蒙牛': 6, '衣服': 7, '计算机': 8, '酒店': 9
print("id_to_cat是:",id_to_cat) #结果为:0: '书籍', 1: '平板', 2: '手机', 3: '水果', 4: '洗发水', 5: '热水器', 6: '蒙牛', 7: '衣服', 8: '计算机', 9: '酒店'


#    ***********对中文预处理************************
#定义删除除字母、数字、汉字以外的所有符号函数
def remove_punctuation(line):
    line = str(line)
    if line.strip() =='':
        return ''
    rule = re.compile(u"[^a-zA-Z0-9\u4E00-\u9FA5]") # unicode中中文的编码为/u4e00-/u9fa5,仅保留大小写字母,数字、中文
    line = rule.sub('',line)
    return line

def stopwordslist(filepath):
    stopwords = [line.strip() for line in open(filepath,'r',encoding='utf-8').readlines()]
    return stopwords

    #加载停用词
stopwords = stopwordslist('D:\PyCharm\PyCharmWorkPlace\WorkPlace1\TextClassification\chineseStopWords.txt')
#删除除字母、数字、汉字之外的所有符号
df['clean_review'] = df['review'].apply(remove_punctuation)
print("随机检验一个实例,输出的结果是:",df.sample(10))


#   **************在clean_review的基础上分词********************
df['cut_review'] = df['clean_review'].apply(lambda x:" ".join([w for w in list(jb.cut(x)) if w not in stopwords])) #中文分词,调用jieba
df.head()
print("df.head()",df.head(10)) #输出cat,以及其对应的分词之后的结果cut_review


#   ****************LSTM建模***********************
#MAX_NB_WORDS = 5000 #针对原数据集设置最频繁使用的5000个词
MAX_NB_WORDS = 500  #
#MAX_SEQUENCE_LENGTH = 250 #针对原数据集每条cut_review最大的长度,超过的将会被截去,不足的将会被补0
MAX_SEQUENCE_LENGTH = 25
EMBEDDING_DIM = 100 #设置Embedding层的维度

#tokenizer = Tokenizer(num_words=MAX_NB_WORDS,filters='!"#$%&()*+,-./:;<=>?@[\]^_{|}~',lower=True)
tokenizer = Tokenizer(num_words=MAX_NB_WORDS,filters='!"#$%&()*+,-./:;<=>?@[\]^_`{|}~',lower=True)
tokenizer.fit_on_texts(df['cut_review'].values)
word_index = tokenizer.word_index
print('共有%s个不相同的词语' %len(word_index))  #共有70974个不相同的词语


X = tokenizer.texts_to_sequences(df['cut_review'].values)
X = pad_sequences(X,maxlen=MAX_SEQUENCE_LENGTH)# 填充X,让X的各个列的长度统一
Y = pd.get_dummies(df['cat_id']).values  #多类标签的one-hot展开

print("X是:",X)
print("Y是:",Y)

#  ******************拆分训练集和测试集*****************************
X_train, X_test,Y_train,Y_test = train_test_split(X,Y,test_size = 0.10,random_state = 42)
print(X_train.shape,Y_train.shape)
print(X_test.shape,Y_test.shape)

#  **********************************定义模型***************************************
model = Sequential()
model.add(Embedding(MAX_NB_WORDS,EMBEDDING_DIM,input_length=X.shape[1]))
model.add(SpatialDropout1D(0.2))
model.add(LSTM(100,dropout = 0.2,recurrent_dropout=0.2))
#model.add(Dense(10, activation='softmax')) #原数据模型,dense_1=10
model.add(Dense(3, activation='softmax')) #根据自己数据时间情况,dense_1=3
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])  #categorical_crossentropy:交叉熵损失函数
print(model.summary())

epochs = 5
batch_size = 64
history = model.fit(X_train,Y_train,epochs=epochs,batch_size=batch_size,validation_split=0.1,
                    callbacks=[EarlyStopping(monitor='val_loss',patience=3,min_delta=0.0001)])

accr = model.evaluate(X_test,Y_test)
print('Test set\nloss:{:0.3f}\n Accuracy:{:0.3f}'.format(accr[0],accr[1])) #loss:0.344,Accuracy:0.885


# ********************打印训练集+测试集损失函数loss的图像******************
plt.title('loss')
plt.plot(history.history['loss'],label='train')
plt.plot(history.history['val_loss'], label = 'test')
plt.legend()
plt.savefig("loss")
plt.show()


# **********************打印测试集+训练集 的准确率Accuracy图像*****************
plt.title('Accuracy')
plt.plot(history.history['acc'],label = 'train')
plt.plot(history.history['val_acc'],label = 'test')
plt.legend()
plt.savefig("Accuracy")
plt.show()


#   **************画混淆矩阵+求F1值,从而判断我们模型的效果****************************88
y_pred = model.predict(X_test)
y_pred = y_pred.argmax(axis=1)
Y_test = Y_test.argmax(axis=1)

import seaborn as sns
from sklearn.metrics import accuracy_score,confusion_matrix
conf_mat = confusion_matrix(Y_test,y_pred) #生成混淆矩阵
fig,ax = plt.subplots(figsize = (12,10))
sns.heatmap(conf_mat,annot=True,fmt='d',xticklabels=cat_id_df.cat.values,yticklabels=cat_id_df.cat.values)
plt.ylabel('实际结果',fontsize = 18)
plt.xlabel('预测结果',fontsize = 18)
plt.text(0.5,51.2344,'预测结果')
plt.savefig("Result")
plt.show()

#  ************************预测结果******************************
from sklearn.metrics import classification_report
print('accuracy %s' %accuracy_score(y_pred, Y_test))
print(classification_report(Y_test,y_pred,target_names=cat_id_df['cat'].values))

#  ************************预测结果结束******************************


#  ************************自定义预测,即输入一句话来判断其所属类别*******************开始***********
def predict(text):
    txt = remove_punctuation(text)  # 对输入的文本做预处理
    txt = [" ".join([w for w in list(jb.cut(text)) if w not in stopwords])]
    seq = tokenizer.texts_to_sequences(txt)
    padded = pad_sequences(seq,maxlen=MAX_SEQUENCE_LENGTH)
    pred = model.predict(padded)
    cat_id = pred.argmax(axis=1)[0]
    return cat_id_df[cat_id_df.cat_id==cat_id]['cat'].values[0]

num = int(input("从键盘输入一个数字"))  #执行的次数是num-1
for num in range(1,num):  # range的取值是[1,num)
    String = input("从键盘输入一句话")
    String1 = predict(String)
    print("第%d预测的种类是:"%num,String1)

# eg:
# 输入:苹果好吃又不贵,已经购买很多次了    ,得到类别是“水果”
# 输入: 假的,不好用,头皮痒的要命           得到的类别是“洗发水”
#  ************************自定义预测,即输入一句话来判断其所属类别***************结束***************

End = datetime.datetime.now()
print("运行结束的时间是:",End)

Run_time = End - Start
print("总共运行的时间是:", End - Start)

在此特别感谢一位网友(链接找不到了,等我找到再来分享),无私分享了自己的程序供我参考学习。

你可能感兴趣的:(文本分类,python)