美文网首页公众号爬虫数据分析
Python 实现小型文本分类系统

Python 实现小型文本分类系统

作者: python与数据分析 | 来源:发表于2019-01-21 10:28 被阅读606次

    最近在做微信公众号采集开发,将要对公众号文章数据(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 实现小型文本分类系统

        本文链接:https://www.haomeiwen.com/subject/iiwqjqtx.html