python文本分类框架_Python 实现小型文本分类系统

最近在做微信公众号采集开发,将要对公众号文章数据(mysql里),进行文本分类,查了很多资料,找到一篇适合新手的一篇博文:https://blog.csdn.net/github_36326955/article/details/54891204,本人提供了人工分好类的文章训练集语料库(1000多篇)和测试集语料库(11篇),和大家一起学习。

一、中文文本分类流程

1、预处理

2、中文分词

3、结构化表示--构建词向量空间

4、权重策略--TF-IDF

5、分类器选择

6、评价

二,具体细节

1,预处理

# 公众号文章类别

d_category = {'1': '人工智能', '2': '人文社科', '3': '信息系统', '4': '先进防御', '5': '兵器', '6': '农业', '7': '前沿交叉', '8': '反恐安全',

'9': '基础科学', '10': '教育', '11': '核生化', '12': '模拟仿真', '13': '海战装备', '14': '生物医学', '15': '电子元器件',

'16': '空战装备', '17': '管理与政策', '18': '经济', '19': '综合保障', '20': '网络空间', '21': '能原材料', '22': '航天',

'23': '试验鉴定', '24': '防务策略', '25': '其他', '26': '太空探索', '27': '招标采购', '28': '区块链', '29': '地理科学'

}

1.1,得到训练集语料库

即已经分好类的文本资料(例如:语料库里是一系列已经分词的txt文章,这些文章按照实际内容归入到不同分类的目录中,为了方便演示,如上所有分类都用数字代表,如 .\1\21.txt),下载链接:https://pan.baidu.com/s/1NgkcztR0d-QPRn9toM1wCA 提取码: dw8h ,将下载的语料库解压后,请自己修改文件名和路径,例如路径可以设为 ./train_corpus/,其下则是各个类别目录如:./train_corpus/1,……,\train_corpus\2

1.2,得到测试语料库

也是已经分好类的文本资料,与1.1类型相同,只是里面的文档不同,用于检测算法的实际效果。下载链接: https://pan.baidu.com/s/18P8hkOEvughxJ9B8M3fbHg 提取码: wqjj ,测试预料可以从1.1中的训练预料中随机抽取,也可以下载独立的测试语料库路径修改参考1.1,上面提供的是独立的测试语料,例如可以设置为 ./test_corpus/

2,中文分词

本文使用的分词工具是jieba,最近新出来的一个分词工具pkuseg。两者区别参考:流程是从mysql读取数据——结巴分词——按分类文件夹存入txt。截止目前,我们已经得到了分词后的训练集语料库和测试集语料库,下面我们要把这两个数据集表示为变量,从而为下面程序调用提供服务。我们采用的是Scikit-Learn库中的Bunch数据结构来表示这两个数据集。

首先来看看Bunch:

Bunch这玩意儿,其实就相当于python中的字典。你往里面传什么,它就存什么。

好了,解释完了。

是不是很简单?

接下来,让我们看看的我们的数据集(训练集)有哪些信息:

image.png

那么,用Bunch表示,就是:

from sklearn.datasets.base import Bunch

bunch = Bunch(target_name=[],label=[],filenames=[],contents=[])

我们在Bunch对象里面创建了有4个成员:

target_name:是一个list,存放的是整个数据集的类别集合。

label:是一个list,存放的是所有文本的标签。

filenames:是一个list,存放的是所有文本文件的名字。

contents:是一个list,分词后文本文件(一个文本文件只有一行)

下面,我们将文本文件转为Bunch类形:

# -*- coding: UTF-8 -*-

import os

import pickle

from sklearn.datasets.base import Bunch

def _readfile(path):

'''读取文件'''

# 函数名前面带一个_,是标识私有函数

# 仅仅用于标明而已,不起什么作用,

# 外面想调用还是可以调用,

# 只是增强了程序的可读性

with open(path, "rb") as fp: # with as句法前面的代码已经多次介绍过,今后不再注释

content = fp.read()

return content

def corpus2Bunch(wordbag_path, seg_path):

catelist = os.listdir(seg_path) # 获取seg_path下的所有子目录,也就是分类信息

# 创建一个Bunch实例

bunch = Bunch(target_name=[], label=[], filenames=[], contents=[])

bunch.target_name.extend(catelist)

# 获取每个目录下所有的文件

for mydir in catelist:

class_path = seg_path + mydir + "/" # 拼出分类子目录的路径

file_list = os.listdir(class_path) # 获取class_path下的所有文件

for file_path in file_list: # 遍历类别目录下文件

fullname = class_path + file_path # 拼出文件名全路径

bunch.label.append(mydir)

bunch.filenames.append(fullname)

bunch.contents.append(_readfile(fullname)) # 读取文件内容

'''append(element)是python list中的函数,意思是向原来的list中添加element,注意与extend()函数的区别'''

# 将bunch存储到wordbag_path路径中

with open(wordbag_path, "wb") as file_obj:

pickle.dump(bunch, file_obj)

if __name__ == "__main__": # 这个语句前面的代码已经介绍过,今后不再注释

# 对训练集进行Bunch化操作:

wordbag_path = "train_word_bag/train_set.dat" # Bunch存储路径

seg_path = "train_corpus/" # 分词后分类语料库路径

corpus2Bunch(wordbag_path, seg_path)

# 对测试集进行Bunch化操作:

wordbag_path = "test_word_bag/test_set.dat" # Bunch存储路径

seg_path = "test_corpus/" # 分词后分类语料库路径

corpus2Bunch(wordbag_path, seg_path)

3,结构化表示--向量空间模型

在第2节中,我们对原始数据集进行了分词处理,并且通过绑定为Bunch数据类型,实现了数据集的变量表示。

4,权重策略--TF-IDF

我们把训练集文本转换成了一个TF-IDF词向量空间,姑且叫它为A空间吧。那么我们还有测试集数据,我们以后实际运用时,还会有新的数据,这些数据显然也要转到词向量空间,那么应该和A空间为同一个空间吗?

是的。

即使测试集出现了新的词汇(不是停用词),即使新的文本数据有新的词汇,只要它不是训练集生成的TF-IDF词向量空间中的词,我们就都不予考虑。这就实现了所有文本词向量空间“大一统”,也只有这样,大家才在同一个世界里。才能进行下一步的研究。

下面的程序就是要将训练集所有文本文件(词向量)统一到同一个TF-IDF词向量空间中(或者叫做用TF-IDF算法计算权重的有权词向量空间)。这个词向量空间最终存放在train_word_bag/tfdifspace.dat中。

把训练集数据成功的构建了一个TF-IDF词向量空间,空间的各个词都是出自这个训练集(去掉了停用词)中,各个词的权值也都一并保存了下来,叫做权重矩阵。

需要注意的是,权重矩阵是一个二维矩阵,a[i][j]表示,第j个词在第i个类别中的IF-IDF值

# 引入Bunch类

from sklearn.datasets.base import Bunch

import pickle

from sklearn.feature_extraction.text import TfidfVectorizer

def _readfile(path):

with open(path, "rb") as fp:

content = fp.read()

return content

def _readbunchobj(path):

with open(path, "rb") as file_obj:

bunch = pickle.load(file_obj)

return bunch

def _writebunchobj(path, bunchobj):

with open(path, "wb") as file_obj:

pickle.dump(bunchobj, file_obj)

def vector_space(stopword_path, bunch_path, space_path, train_tfidf_path=None):

stpwrdlst = _readfile(stopword_path).splitlines()

bunch = _readbunchobj(bunch_path)

tfidfspace = Bunch(target_name=bunch.target_name, label=bunch.label, filenames=bunch.filenames, tdm=[],

vocabulary={})

if train_tfidf_path is not None:

trainbunch = _readbunchobj(train_tfidf_path)

tfidfspace.vocabulary = trainbunch.vocabulary

vectorizer = TfidfVectorizer(stop_words=stpwrdlst, sublinear_tf=True, max_df=0.5,

vocabulary=trainbunch.vocabulary)

tfidfspace.tdm = vectorizer.fit_transform(bunch.contents)

else:

vectorizer = TfidfVectorizer(stop_words=stpwrdlst, sublinear_tf=True, max_df=0.5)

tfidfspace.tdm = vectorizer.fit_transform(bunch.contents)

tfidfspace.vocabulary = vectorizer.vocabulary_

_writebunchobj(space_path, tfidfspace)

print("if-idf词向量空间实例创建成功!!!")

if __name__ == '__main__':

stopword_path = "train_word_bag/hlt_stop_words.txt"

bunch_path = "train_word_bag/train_set.dat"

space_path = "train_word_bag/tfdifspace.dat"

vector_space(stopword_path, bunch_path, space_path)

bunch_path = "test_word_bag/test_set.dat"

space_path = "test_word_bag/testspace.dat"

train_tfidf_path = "train_word_bag/tfdifspace.dat"

vector_space(stopword_path, bunch_path, space_path, train_tfidf_path)

上面的代码运行之后,会将训练集数据转换为TF-IDF词向量空间中的实例,保存在train_word_bag/tfdifspace.dat中,具体来说,这个文件里面有两个我们感兴趣的东西,一个是vocabulary,即词向量空间坐标,一个是tdm,即训练集的TF-IDF权重矩阵。

接下来,我们要开始第5步的操作,设计分类器,用训练集训练,用测试集测试。在做这些工作之前,你一定要记住,首先要把测试数据也映射到上面这个TF-IDF词向量空间中,也就是说,测试集和训练集处在同一个词向量空间(vocabulary相同),只不过测试集有自己的tdm,与训练集(train_word_bag/tfdifspace.dat)中的tdm不同而已。

5,分类器

这里我们采用的是朴素贝叶斯分类器,今后我们会详细讲解它。

现在,你即便不知道这是个啥玩意儿,也一点不会影响你,这个分类器我们有封装好了的函数,MultinomialNB,这玩意儿获取训练集的权重矩阵和标签,进行训练,然后获取测试集的权重矩阵,进行预测(给出预测标签)。

下面我们开始动手实践吧!

首先,我们要把测试数据也映射到第4节中的那个TF-IDF词向量空间上:

import pickle

from sklearn.naive_bayes import MultinomialNB # 导入多项式贝叶斯算法

# 读取bunch对象

def _readbunchobj(path):

with open(path, "rb") as file_obj:

bunch = pickle.load(file_obj)

return bunch

# 导入训练集

trainpath = "train_word_bag/tfdifspace.dat"

train_set = _readbunchobj(trainpath)

# 导入测试集

testpath = "test_word_bag/testspace.dat"

test_set = _readbunchobj(testpath)

# 训练分类器:输入词袋向量和分类标签,alpha:0.001 alpha越小,迭代次数越多,精度越高

clf = MultinomialNB(alpha=0.001).fit(train_set.tdm, train_set.label)

# 预测分类结果

predicted = clf.predict(test_set.tdm)

for file_name, expct_cate in zip(test_set.filenames, predicted):

# if flabel != expct_cate:

print(file_name, " -->预测类别:", expct_cate)

print("预测完毕!!!")

结果:

image.png

6,评价与小结

评价部分的实际操作我们已经在上一节的代码中给出了。这里主要是要解释一下代码的含义,以及相关的一些概念。

截止目前,我们已经完成了全部的实践工作。接下来,你或许希望做的是:

1,分词工具和分词算法的研究

2,文本分类算法的研究

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