文本分类入门实战

多模态情感分析——文本分类入门实战

环境:python3.8
CSDN训练数据地址:https://download.csdn.net/download/weixin_45889655/49100825免费积分的审核了三天,有积分的审核了两分钟。大家有条件或者着急用的去淘宝可以下个单,免费的审核不过啊、
没条件的或者不怕百度网盘慢的,挂个链接:链接:https://pan.baidu.com/s/1KTvvISFlfNgfcs9Ynk03Cw
提取码:1024
gitee地址为:https://gitee.com/huadeng863/text-classifier-practice
可以运行体验一下,一般一个py文件要运行5-6分钟,可以对照文章截图理解一下自然语言处理的实际操作。
为了方便立即将文章分为几个部分来讲解。

第一步:划分训练集和测试集(choosed.py)

数据已经全部放入data文件夹中,data文件夹下有九大类新闻文本,
在这里插入图片描述
每个新闻分类中是他的所有新闻样例,一条新闻单独一个txt文件,文件均有序号标注。
在这里插入图片描述
通过对所有数据样本进行统计:
在这里插入图片描述
可以发现样本成不均匀分布,为了保证训练模型中不会偏向某个分类,因此要保证不同分类的训练样本数目一致,所以,最后随机从每个分类中取5000条。并最终以8:2划分训练集和测试集。
实现代码及注释如下:

import os
import random
import shutil
path='./data/'
cate_list = os.listdir(path)  # 获取未分词语料库中所有类别
for mydir in cate_list:
    train_dir = './train_corpus/' + mydir + "/"  # 拼出训练集存贮的对应目录路径如:train_corpus/体育/
    if not os.path.exists(train_dir):  # 是否存在分词目录,如果没有则创建该目录
        os.makedirs(train_dir)

    test_dir = './test_corpus/' + mydir+'/' # 拼出测试存贮的对应目录路径如:test_corpus/体育/
    if not os.path.exists(test_dir):
        os.makedirs(test_dir)
    class_path=path+mydir+'/' # 生成当前类别的目录 如 data/体育/
    file_list=os.listdir(class_path) # 生成分类下文本名称列表
    length=len(file_list)
    print(mydir,length)
    res = random.sample(range(1, length+1), 5000) #在所有文件中随机选取五千个生成索引列表,乱序
    train=res[0:4000]#训练集占80%,4000条
    test=res[4000:5000]#测试集占20%,1000条
    #print(len(train),len(test))
    for file_path in file_list:
        fullname = class_path + file_path  # 拼出文件名全路径如:data/体育/21.txt
        #print(file_path)
        x=int(file_path.split('.')[0].split('_')[1])#将文件名中的序号取出
        if x in train:
           shutil.copyfile(fullname, train_dir+file_path)#将前面的文件复制到后面的目录中
        if x in test:
           shutil.copyfile(fullname, test_dir + file_path)

执行choosed.py文件划分前:
在这里插入图片描述
划分后将data文件分成两部分(训练集和测试集):
在这里插入图片描述

第二步:语料分词(corpus_segment.py)

之前已经介绍过分词的jieba库,所以直接上手就可以了。
实现代码及注释如下:

import os
import jieba
from Tools import savefile, readfile

def corpus_segment(corpus_path, seg_path):
    catelist = os.listdir(corpus_path)  # 获取corpus_path下的所有子目录
    #print(catelist)
    '''
    其中子目录的名字就是类别名,例如:
    train_corpus/体育/21.txt中,'train_corpus/'是corpus_path,'体育'是catelist中的一个成员
    '''
    # 获取每个目录(类别)下所有的文件
    for mydir in catelist:
        class_path = corpus_path + mydir + "/"  # 拼出分类子目录的路径如:train_corpus/体育/
        seg_dir = seg_path + mydir +  "/" # 拼出分类分词目录的路径如:train_seg/体育/
        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  # 拼出文件名全路径如:train_corpus/art/21.txt
            content = readfile(fullname)  # 读取文件内容
            '''此时,content里面存贮的是原文本的所有字符,例如多余的空格、空行、回车等等,
            接下来,我们需要把这些无关痛痒的字符统统去掉,变成只有标点符号做间隔的紧凑的文本内容
            为了保证大量文本的读取速度,Tools封装的readfiles为rb方法,也就是二进制的读写,所以需要转成'utf-8'编码
            '''
            content = content.replace('\r\n'.encode('utf-8'), ''.encode('utf-8')).strip()  # 删除换行
            content = content.replace(' '.encode('utf-8'), ''.encode('utf-8')).strip()  # 删除空行、多余的空格
            content_seg =jieba.cut(content) # 为文件内容分词
            savefile(seg_dir + file_path, ' '.join(content_seg).encode('utf-8'))  # 将处理后的文件保存到分词后语料目录

if __name__ == "__main__":

    seg_path = "./train_corpus_seg/"#分词之后的语料库储存路径
    corpus_path = "./train_corpus/"#需要分词的语料库路径
    corpus_segment(corpus_path, seg_path)
    print("训练语料分词结束!!!")
    seg_path = "./test_corpus_seg/"  # 分词之后的语料库储存路径
    corpus_path = "./test_corpus/"  # 需要分词的语料库路径
    corpus_segment(corpus_path, seg_path)
    print("测试语料分词结束!!!")

执行corpus_segment.py.py文件分词前:
在这里插入图片描述
分词后(将训练预料和测试语料分词后放入seg文件夹中):
在这里插入图片描述

第三步:bunch化操作(corpus2Bunch.py)

Bunch本质上的数据类型是dict字典类型,在这里为了方便处理将每个文本的分类类别,文件名路径,文件内容(已分词)转换成一个个的字典类型方便后续处理。
实现代码及注释如下:

import os
import pickle
from sklearn.datasets._base import Bunch
from Tools import readfile

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)
    '''
    extend(addlist)是python list中的函数,意思是用新的list(addlist)去扩充
    原来的list
    '''
    # 获取每个目录下所有的文件
    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)
    print("构建文本对象结束!!!")


if __name__ == "__main__":
    # 对训练集进行Bunch化操作:
    wordbag_path = "train_word_bag/train_set.dat"  # Bunch存储路径
    if not os.path.exists("train_word_bag"):  # 是否存在分词目录,如果没有则创建该目录
        os.makedirs("train_word_bag")
    seg_path = "train_corpus_seg/"  # 分词后分类语料库路径
    corpus2Bunch(wordbag_path, seg_path)

    # 对测试集进行Bunch化操作:
    wordbag_path = "test_word_bag/test_set.dat"  # Bunch存储路径
    if not os.path.exists("test_word_bag"):  # 是否存在分词目录,如果没有则创建该目录
        os.makedirs("test_word_bag")
    seg_path = "test_corpus_seg/"  # 分词后分类语料库路径
    corpus2Bunch(wordbag_path, seg_path)

执行corpus2Bunch.py,bunch前:
在这里插入图片描述
bunch化后多出两个词袋文件夹,里面存放的是所有训练集、测试集集成好得一个dat文件,方便了后续的处理、
在这里插入图片描述

第四步:构建TF-IDF向量空间(TFIDF_space.py)

这一步包括了去停用词,特征工程和特征选择。这部分的理论在上一篇文章做了简单的介绍,而且这个方法已经在python的sklearn中封装好了方法。
实现代码及注释如下:

from sklearn.datasets._base import Bunch
from sklearn.feature_extraction.text import TfidfVectorizer
from Tools import readfile, readbunchobj, writebunchobj

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)
        '''
        #.stop_words=list类型,直接过滤指定的停用词。
        # sublinear_tf:,计算tf值采用亚线性策略。比如,我们以前算tf是词频,现在用1+log(tf)来充当词频。
        #max_df,过滤出现在超过max_df=0.5比例的句子中的词语,当他在全文档出现的频次过多>50%时我们认为他太过常见而不具备代表性
        # .vocabulary: dict类型,只使用特定的词汇,为了避免在测试集中出现训练集中没有出现的词汇而造成困扰所以一般会用这个,但是如果训练集足够大可以不用
        '''
        tfidfspace.tdm = vectorizer.fit_transform(bunch.contents)

    else:
        vectorizer = TfidfVectorizer(stop_words=stpwrdlst, sublinear_tf=True, max_df=0.5)
        '''
        #.stop_words=list类型,直接过滤指定的停用词。
        # sublinear_tf:,计算tf值采用亚线性策略。比如,我们以前算tf是词频,现在用1+log(tf)来充当词频。
        # max_df,过滤出现在超过max_df=0.5比例的句子中的词语,当他在全文档出现的频次过多>50%时我们认为他太过常见而不具备代表性
        '''
        tfidfspace.tdm = vectorizer.fit_transform(bunch.contents)
        tfidfspace.vocabulary = vectorizer.vocabulary_

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


if __name__ == '__main__':
    stopword_path = "hit_stopwords.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向量空间实例,嫌麻烦就不展示了。

第五步:训练模型

在sklearn中已经封装好的库直接调用就可以了。

from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import MultinomialNB  # 导入多项式贝叶斯算法
from sklearn import metrics
from Tools import readbunchobj
import os

# 导入训练集
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)
#clf = LogisticRegression(C=1000.0).fit(train_set.tdm, train_set.label)
print("训练完毕!!!")
# 预测分类结果
predicted = clf.predict(test_set.tdm)

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


# 计算分类精度:

def metrics_result(actual, predict):
    print('精度:{0:.3f}'.format(metrics.precision_score(actual, predict, average='weighted')))
    print('召回:{0:0.3f}'.format(metrics.recall_score(actual, predict, average='weighted')))
    print('f1-score:{0:.3f}'.format(metrics.f1_score(actual, predict, average='weighted')))


metrics_result(test_set.label, predicted)

之前理论介绍的是朴素贝叶斯模型,但是走到这一步发现朴素贝叶斯和TF-IDF的相适性并不好,至少逻辑回归比他更合适。但是都走到这一步我是不想换模型的。先试一下贝叶斯的效果。
在这里插入图片描述

再看看逻辑回归的效果:
在这里插入图片描述
精确度上全面溃败。但是你实际运行会发现贝叶斯运行的比逻辑回归要快很多,虽然精确度才是王道。

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值