• 郑捷《机器学习算法原理与编程实践》学习笔记(第二章 中文文本分类(一))


      2.1 文本挖掘与文本分类的概念

      文本挖掘是指从大量的文本数据中抽取事先未知的、可理解的、最终可用的知识的过程,同时运用这些知识更好的组织信息以便将来参考。

    • 搜索和信息检索(IR):存储和文本文档的检索,包括搜索引擎个关键字搜索
    • 文本聚类:使用聚类方法,对词汇、片段、段落或文件进行分组和归类
    • 文本分类:对片段、段落或文件进行分组和归类,在使用数据挖掘分类方法的基础上,经过训练的标记示例模型。
    • Web挖掘:在互联网上进行数据和文本的挖掘,并特别关注网络的规模和相互的联系。
    • 信息抽取(IE):从非结构化文本中识别与提取有关的事实和关系:从非结构化或半结构化文本中抽取结构化数据的过程。
    • 自然语言处理(NLP):将语言作为一种有意义、有规则的符号系统,从底层解析和理解语言的任务(例如词性的标注);目前的技术方法主要从语法、语义的角度发现语言最本质的结构和所表达的意义。
    • 概念的提取:把单词和短语按语义分成意义相似的组

      2.2 文本分类项目

      文本分类的一般步骤:

      (1)预处理:去除文本的噪声信息,例如HTML标签、文本的格式转换、检测句子边界等。

      (2)中文分词:使用中文分词器为文本分词,并去除停用词。

      (3)构建词向量空间:统计文本词频,生成文本的词向量空间。

      (4)权重策略—TF-IDF方法:使用TF-IDF发现特征词,并抽取为反应文档主题的特征。

      (5)分类器:使用算法训练分类器。

      (6)评价分类结果:分类器的测试结果分析

      2.2.1 文本预处理

      1.选择处理的文本的范围

      2.建立分类文本语料库

      中文文本分类语料库下载地址为:http://www.datatang.com/datares/go.aspx?dataid=602146

      3.文本格式转换

      Python去除HTML标签,一般使用lxml

      

    #coding:utf-8
    from lxml import etree,html
    import chardet
    
    #HTML文件路径,以及读取文件
    path = '1.html'
    content = open(path,"rb").read()
    print type(content)
    page = html.document_fromstring(content)#解析文件
    text = page.text_content()#去除所有标签
    # print type(text)
    # print chardet.detect(text)
    print text #输出去除标签后的解析结果

      4.检测句子边界:标记句子的结束

      2.2.2 中文分词介绍

      文本的结构化表示简单分为四大类:词向量空间模型、主题模型、依存句法的树表示、RDF的图表示

      jieba分词简单的样例代码

      

    #jieba分词
    #coding:utf-8
    import sys
    import os
    import jieba
    
    #设置UTF-8 Unicode环境
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    seg_list = jieba.cut("小明1995年毕业于北京清华大学",cut_all=False)
    print "Default Mode:"," ".join(seg_list)#默认切分
    
    seg_list = jieba.cut("小明1995年毕业于北京清华大学",cut_all=True)
    print "Full Mode:"," /".join(seg_list)#默认切分
    
    #搜索引擎模式
    seg_list = jieba.cut_for_search("小明1995年毕业于北京清华大学")
    print "search:"," /".join(seg_list)#默认切分
    
    #词性标注
    import jieba.posseg as pseg
    words =pseg.cut("我爱北京天安门")
    for w in words:
        print w.word,w.flag

    Prefix dict has been built succesfully.
     小明 1995 年 毕业 于 北京 清华大学
    Full Mode: 小 /明 /1995 /年 /毕业 /于 /北京 /清华 /清华大学 /华大 /大学
    search: 小明 /1995 /年 /毕业 /于 /北京 /清华 /华大 /大学 /清华大学
    我 r
    爱 v
    北京 ns
    天安门 ns

       本项目创建分词后,语料路径为Root rain_corpus_seg.

      (1)设置字符集,并导入jieba分词包

      

    #coding:utf-8
    import sys
    import os
    import jieba
    
    #设置UTF-8 Unicode环境
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    #定义两个函数读取和保存文件
    def savefile(savepath,content):#保存至文件
        fp      = open(savepath,"wb")
        fp.write(content)
        fp.close()
    
    def readfile(path):
       fp      = open(path,"rb")
       content = fp.read()
       fp.close()
       return content
    
    #整个语料库分词的主程序
    #未分词分类语料库路径
    #分词后的分类语料库路径
    corpus_path = "WorkSpace/TextClassification/train_corpus_small/"
    seg_path    = "WorkSpace/TextClassification/train_corpus_seg/"
    
    #获取corpus_path下的所有子目录
    catelist    = os.listdir(corpus_path)
    for mydir in catelist:
        #拼出分类子目录的路径
        class_path = corpus_path+mydir+"/"
        #拼出分词后的语料分类目录
        seg_dir   = seg_path+mydir+"/"
        #是否存在目录,如果没有则创建
        if not os.path.exists(seg_dir):
            os.makedirs(seg_dir)
        #获得类别目录下的所有文件
        file_list = os.listdir(class_path)
        #遍历类别目录下的所有文件
        for file_path in file_list:
            #拼出文件名的全路径
            fullname    = class_path + file_path
            #读取文件的内容
            content     = readfile(fullname).strip()
            #删除换行和多余的空格
            content     = content.replace("
    ","").strip()
            #为文件的内容分词
            content_seg = jieba.cut(content)
            #将处理后的文件保存到分词后的语目录
            savefile(seg_dir+file_path,"".join(content_seg))
    print u"中文语料分析结束!!!"

      在实际应用中,为了后续的生成空间模型的方便,这些分词后的文本信息还要转化为文本向量信息并对象化需要引入Scikit-Learn库的Bunch的数据结构:

      

    import sys
    import os
    import jieba
    from sklearn.datasets.base import Bunch#Bunch类
    import cPickle as pickle
    '''
    Bunch类提供了一种key,value的对象形式
    target_name:所有分类集名称列表
    label每个文件的分类标签列表
    filename:文件路径
    contents:分词后文件词向量形式
    '''
    
    def readfile(path):
       fp      = open(path,"rb")
       content = fp.read()
       fp.close()
       return content
    
    bunch = Bunch(target_name = [],label = [],filename = [],contents = [])
    #将分好词的文本文件转换并持久化为Bunch类形式的代码如下:
    #分词语料Bunch对象持久化文件路径
    wordbag_path = "WorkSpace/TextClassification/train_word_bag/train_set.dat"
    seg_path     = "WorkSpace/TextClassification/train_corpus_seg/"   #分词后分类语料库路径
    
    catelist     = os.listdir(seg_path)    #
    bunch.target_name.extend(catelist)     #按类别信息保存到Bunch对象中
    for mydir in catelist:
        class_path   = seg_path + mydir + "/"
        file_list    = os.listdir(class_path)
        for file_path in file_list:
            fullname = class_path + file_path
            bunch.label.append(mydir)#保存当前文件的分类标签
            bunch.filename.append(fullname)#保存当前文件路径
            bunch.contents.append(readfile(fullname).strip())#保存文件词向量
    #Bunch对象的持久化
    file_obj = open(wordbag_path,"wb")
    pickle.dump(bunch,file_obj)
    file_obj.close()
    
    print u"构建文本对象结束!!!"

      2.2.3 Scikit-Learn库简介

      2.2.4 向量空间模型

      可以从http://www.threedweb.cn/thread-1294-1-1.html

      读取停用词:

    #读取停用词列表代码
    stopword_path = "WorkSpace/TextClassification/train_word_bag/hlt_stop_words.txt"
    stpwrdlst     = readfile(stopword_path).splitlines()

      2.2.5 权重策略:TD-IDF方法

      含义:如果某个词或短语在一篇文章中出现的频率越高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。

      词频(Term Frequency,TF)指的是某一个给定的词语在该文件中出现的频率。这个数字是对词数(Term Count)的归一化,以防止它偏向长的文件。对于在某一特定文件里的词语来说,它的重要性可以表示为:

      

      其中,分子是该词在文件中出现的次数,分母是文件中所有字词的出现次数之和:

      逆向文件频率(Inverse Document Frequency,IDF)是一个词语普遍重要性的度量。某一特定词语的IDF,可以由总文件数目除以包含该词语的文件的数目,再将得到的商取对数得到:

      

    • 其中|D|:语料库中的文件总数。
    • j:包含词语的文件数目。如果该词语不在语料库中,就会导致分母为零,因此一般情况下使用1+j作为分母

      TF-IDF = TF *IDF

      2.代码的实现

      

    import sys
    import os
    from sklearn.datasets.base import Bunch
    import cPickle as pickle
    from sklearn import feature_extraction
    from sklearn.feature_extraction.text import TfidfTransformer #TF-IDF向量转换类
    from sklearn.feature_extraction.text import TfidfVectorizer
    
    #配置utf-8输出环境
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    def readfile(path):
       fp      = open(path,"rb")
       content = fp.read()
       fp.close()
       return content
    
    stopword_path = "WorkSpace/TextClassification/train_word_bag/hlt_stop_words.txt"
    stpwrdlst     = readfile(stopword_path).splitlines()
    
    #1.读取和写入Bunch对象的函数
    def readbunchobj(path):
        file_obj = open(path,"rb")
        bunch    = pickle.load(file_obj)
        file_obj.close()
        return bunch
    
    #写入Bunch对象
    def writebunchobj(path,bunchobj):
        file_obj = open(path,"wb")
        pickle.dump(bunchobj,file_obj)
        file_obj.close()
    
    #从训练集生成TF-IDF向量词袋
    #2.导入分词后的词向量Bunch对象
    
    path       = "WorkSpace/TextClassification/train_word_bag/train_set.dat"#词向量空间保存路径
    bunch      = readbunchobj(path)
    
    #3.构建TF-IDF向量空间模型
    tfidfspace = Bunch(target_name = bunch.target_name,label = bunch.label,
                       filename = bunch.filename,tdm = [],vocabulary = {})
    #使用TfidfVectorizer初始化向量空间模型
    vectorizer = TfidfVectorizer(stop_words = stpwrdlst,sublinear_tf = True,max_df = 0.5)
    transform  = TfidfTransformer()#该类会统计每个词语放入Tf-IDF权重
    
    #4.文本转化为词频矩阵:单独保存字典文件
    tfidfspace.tdm        = vectorizer.fit_transform(bunch.contents)
    tfidfspace.vocabulary = vectorizer.vocabulary_
    
    #5.创建词袋的持久化
    space_path = "WorkSpace/TextClassification/train_word_bag/tfidfspace.dat"#词向量词袋的保存路径
    writebunchobj(space_path,tfidfspace)

       2.2.6 使用朴素贝叶斯分类模块

      最常用的文本分类方法有KNN最近邻算法、朴素贝叶斯算法和支持向量机算法。一般来说,KNN最近邻算法的原理最简单,分类精度尚可,但速度最慢,朴素贝叶斯算法对于短文文本分类效果最好,精度最高;支持向量机算法的优势是支持线性不可分的情况,精度上取中。

      测试集随机抽取子训练集中的文档集合,每个分类取10个文档,过滤掉1KB以下的文档。

      训练步骤与训练集相同,首先是分词,之后生成文件词向量文件,直至生成词向量模型。不同的是,在训练词向量模型时,需要加载训练集词袋,将测试集产生的词向量映射到训练集词袋的词典中,生成向量空间模型。

      

    #coding:utf-8
    import sys
    import os
    from sklearn.datasets.base import Bunch
    import cPickle as pickle
    from sklearn import feature_extraction
    from sklearn.feature_extraction.text import TfidfTransformer #TF-IDF向量转换类
    from sklearn.feature_extraction.text import TfidfVectorizer
    
    #设置UTF-8 Unicode环境
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    def readfile(path):
       fp      = open(path,"rb")
       content = fp.read()
       fp.close()
       return content
    
    stopword_path = "../WorkSpace/TextClassification/train_word_bag/hlt_stop_words.txt"
    stpwrdlst     = readfile(stopword_path).splitlines()
    
    #1.读取和写入Bunch对象的函数
    def readbunchobj(path):
        file_obj = open(path,"rb")
        bunch    = pickle.load(file_obj)
        file_obj.close()
        return bunch
    
    def writebunchobj(path,bunchobj):
        file_obj = open(path,"wb")
        pickle.dump(bunchobj,file_obj)
        file_obj.close()
    
    #2.导入分词后的词向量Bunch对象
    path          = "../WorkSpace/TextClassification/test_word_bag/test_set.dat"#词向量空间保存路径
    bunch         = readbunchobj(path)
    
    #3.构建测试集TF-IDF向量空间
    testspace     = Bunch(target_name = bunch.target_name,label = bunch.label,filenames = 
                          bunch.filename,tdm = [],vocabulary = {})
    
    #4.导入训练集词袋
    trainbunch    = readbunchobj("../WorkSpace/TextClassification/train_word_bag/tfidfspace.dat")
    
    #5.使用TfidfVectorizer初始化向量空间模型
    vectorizer    = TfidfVectorizer(stop_words = stpwrdlst,sublinear_tf = True ,max_df = 0.5,
                                    vocabulary = trainbunch.vocabulary) #使用训练集词袋向量
    transformer   = TfidfTransformer()
    testspace.tdm = vectorizer.fit_transform(bunch.contents)
    testspace.vocabulary = trainbunch.vocabulary
    
    #6.创建词袋的持久化
    space_path    = "../WorkSpace/TextClassification/test_word_bag/testspace.dat"
    writebunchobj(space_path,testspace)

      测试集数据的处理:

      

    # (1)设置字符集,并导入jieba分词包
    # coding:utf-8
    import sys
    import os
    import jieba
    
    #设置UTF-8 Unicode环境
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    #定义两个函数读取和保存文件
    def savefile(savepath,content):#保存至文件
        fp      = open(savepath,"wb")
        fp.write(content)
        fp.close()
    
    def readfile(path):
       fp      = open(path,"rb")
       content = fp.read()
       fp.close()
       return content
    
    #整个语料库分词的主程序
    #未分词分类语料库路径
    #分词后的分类语料库路径
    corpus_path = "../WorkSpace/TextClassification/test_corpus/"
    seg_path    = "../WorkSpace/TextClassification/test_corpus_seg/"
    
    #获取corpus_path下的所有子目录
    catelist    = os.listdir(corpus_path)
    for mydir in catelist:
        #拼出分类子目录的路径
        class_path = corpus_path+mydir+"/"
        #拼出分词后的语料分类目录
        seg_dir   = seg_path+mydir+"/"
        #是否存在目录,如果没有则创建
        if not os.path.exists(seg_dir):
            os.makedirs(seg_dir)
        #获得类别目录下的所有文件
        file_list = os.listdir(class_path)
        #遍历类别目录下的所有文件
        for file_path in file_list:
            #拼出文件名的全路径
            fullname    = class_path + file_path
            #读取文件的内容
            content     = readfile(fullname).strip()
            #删除换行和多余的空格
            content     = content.replace("
    ","").strip()
            #为文件的内容分词
            content_seg = jieba.cut(content)
            #将处理后的文件保存到分词后的语目录
            savefile(seg_dir+file_path,"".join(content_seg))
    print u"中文语料分析结束!!!"
    
    import sys
    import os
    import jieba
    from sklearn.datasets.base import Bunch#Bunch类
    import cPickle as pickle
    '''
    Bunch类提供了一种key,value的对象形式
    target_name:所有分类集名称列表
    label每个文件的分类标签列表
    filename:文件路径
    contents:分词后文件词向量形式
    '''
    
    def readfile(path):
       fp      = open(path,"rb")
       content = fp.read()
       fp.close()
       return content
    
    bunch = Bunch(target_name = [],label = [],filename = [],contents = [])
    #将分好词的文本文件转换并持久化为Bunch类形式的代码如下:
    #分词语料Bunch对象持久化文件路径
    wordbag_path = "../WorkSpace/TextClassification/test_word_bag/test_set.dat"
    seg_path     = "../WorkSpace/TextClassification/test_corpus_seg/"   #分词后分类语料库路径
    
    catelist     = os.listdir(seg_path)    #
    bunch.target_name.extend(catelist)     #按类别信息保存到Bunch对象中
    for mydir in catelist:
        class_path   = seg_path + mydir + "/"
        file_list    = os.listdir(class_path)
        for file_path in file_list:
            fullname = class_path + file_path
            bunch.label.append(mydir)#保存当前文件的分类标签
            bunch.filename.append(fullname)#保存当前文件路径
            bunch.contents.append(readfile(fullname).strip())#保存文件词向量
    #Bunch对象的持久化
    file_obj = open(wordbag_path,"wb")
    pickle.dump(bunch,file_obj)
    file_obj.close()
    
    print u"构建文本对象结束!!!" 

      

      执行朴素贝叶斯训练:

      

    import cPickle as pickle
    from sklearn.naive_bayes import MultinomialNB #导入多项式贝叶斯算法包
    
    def readbunchobj(path):
        file_obj = open(path,"rb")
        bunch    = pickle.load(file_obj)
        file_obj.close()
        return bunch
    
    #导入训练向量空间
    trainpath = "../WorkSpace/TextClassification/train_word_bag/tfidfspace.dat"
    train_set = readbunchobj(trainpath)
    
    #导入测试集向量空间
    testpath  = "../WorkSpace/TextClassification/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)
    total     = len(predicted)
    rate      = 0
    for flabel,file_name,expct_cate in zip(test_set.label,test_set.filenames,predicted):
        if flabel != expct_cate:
            rate  += 1
            print file_name,u":实际类别:",flabel,u"-->预测类别:",expct_cate
    #精度
    print "error rate:",float(rate)*100/float(total),"%"
    
    输出结果:
    import cPickle as pickle
    from sklearn.naive_bayes import MultinomialNB #导入多项式贝叶斯算法包
    
    def readbunchobj(path):
        file_obj = open(path,"rb")
        bunch    = pickle.load(file_obj)
        file_obj.close()
        return bunch
    
    #导入训练向量空间
    trainpath = "../WorkSpace/TextClassification/train_word_bag/tfidfspace.dat"
    train_set = readbunchobj(trainpath)
    
    #导入测试集向量空间
    testpath  = "../WorkSpace/TextClassification/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)
    total     = len(predicted)
    rate      = 0
    for flabel,file_name,expct_cate in zip(test_set.label,test_set.filenames,predicted):
        if flabel != expct_cate:
            rate  += 1
            print file_name,u":实际类别:",flabel,u"-->预测类别:",expct_cate
    #精度
    print "error rate:",float(rate)*100/float(total),"%"

    输出结果:

     ......

       ../WorkSpace/TextClassification/test_corpus_seg/sport/996.txt :实际类别: sport -->预测类别: art

       ../WorkSpace/TextClassification/test_corpus_seg/sport/997.txt :实际类别: sport -->预测类别: art

       error rate: 13.7777777778 %

      2.2.7 分类结果评估

      (1)召回率(Recall Rate,也叫查全率):是检索出相关文档数和文档库中所有相关文档的比率,衡量的是检索系统的查全率

        召回率(Recall) = 系统检索到的相关文件/系统所有相关的文件的总数

      (2)准确率(Precision,也成称为精度):是检索出的相关文档数与检索出的文档总数的比率,衡量的是检索系统的查准率。

        准确率(Precision) = 系统检索到的相关文件/系统所有检索到的文档总数

      

      (3)Fβ-Mesure(又称为F-Score):是机器学习领域常用的评价标准,计算公式:

          

      其中,β是参数,p是准确率,R是召回率

      当β=1时,就是最常见的F1-Mesure了:

      文本分类结果评估,代码如下:

      

    import numpy as np
    from sklearn import metrics
    
    #定义分类精确度
    def metrics_result(actual,predict):
        print u"精度:{0:.3f}".format(metrics.precision_score(actual,predict))
        print u"召回:{0:.3f}".format(metrics.recall_score(actual,predict))
        print u"f1-score:{0:.3f}".format(metrics.f1_score(actual,predict))
    
    metrics_result(test_set.label,predicted)

    输出结果如下:

    精度:0.881

    召回:0.862

    f1-score:0.860 

    资料来源及相关版权所有:《机器学习算法原理与编程实践》 郑捷

  • 相关阅读:
    洛谷P2912 [USACO08OCT]牧场散步Pasture Walking [2017年7月计划 树上问题 01]
    洛谷P1082 同余方程 [2012NOIP提高组D2T1] [2017年6月计划 数论06]
    洛谷P2667 超级质数 [2017年6月计划 数论05]
    洛谷P1965 转圈游戏 [2013NOIP提高组 D1T1][2017年6月计划 数论04]
    洛谷P1595 信封问题
    洛谷P1062 数列 [2017年6月计划 数论03]
    洛谷P2835 刻录光盘 [2017年6月计划 强连通分量02]
    洛谷P2826 [USACO08NOV]光开关Light Switching [2017年6月计划 线段树02]
    【模板】矩阵快速幂 洛谷P2233 [HNOI2002]公交车路线
    【模板】ST表 洛谷P1816 忠诚
  • 原文地址:https://www.cnblogs.com/wuchuanying/p/6227898.html
走看看 - 开发者的网上家园