2021-4月Python 机器学习——中文新闻文本标题分类

本文涉及的产品
函数计算FC,每月15万CU 3个月
简介: 2021-4月Python 机器学习——中文新闻文本标题分类

试题说明

试题说明

任务描述

基于THUCNews数据集的文本分类, THUCNews是根据新浪新闻RSS订阅频道2005~2011年间的历史数据筛选过滤生成,包含74万篇新闻文档,参赛者需要根据新闻标题的内容用算法来判断该新闻属于哪一类别

数据说明

THUCNews是根据新浪新闻RSS订阅频道2005~2011年间的历史数据筛选过滤生成,包含74万篇新闻文档(2.19 GB),均为UTF-8纯文本格式。在原始新浪新闻分类体系的基础上,重新整合划分出14个候选分类类别:财经、彩票、房产、股票、家居、教育、科技、社会、时尚、时政、体育、星座、游戏、娱乐。

已将训练集按照“标签ID+\t+标签+\t+原文标题”的格式抽取出来,可以直接根据新闻标题进行文本分类任务,希望答题者能够给出自己的解决方案。

训练集格式 标签ID+\t+标签+\t+原文标题 测试集格式 原文标题

提交答案

考试提交,需要提交模型代码项目版本和结果文件。结果文件为TXT文件格式,命名为result.txt,文件内的字段需要按照指定格式写入。

1.每个类别的行数和测试集原始数据行数应一一对应,不可乱序
2.输出结果应检查是否为83599行数据,否则成绩无效
3.输出结果文件命名为result.txt,一行一个类别,样例如下:

···

游戏

财经

时政

股票

家居

科技

社会

房产

教育

星座

科技

股票

游戏

财经

时政

股票

家居

科技

社会

房产

教育

···

一共七个数据集

dict.txt //代表各个ID数字段对应的数字

shuffle_Train_IDs_ //74万篇新闻文档

Test.txt //测试集的标题

Test_IDs.txt //测试集对应的代码

Train.txt //训练集对应的标签ID+\t+标签+\t+原文标题

Train_IDs.txt //训练集对应的代码

Val_IDs.txt //验证集

前期构思:

项目应用到python机器学习对数据进行分类回归

那么分类算法有哪几类?

逻辑回归

线性判别分析

K近邻

分类和回归树

朴素贝叶斯

支持向量机

开始代码实现(想到哪写到哪)

train_data=pd.read_csv(‘cnews_train.txt’,sep=’\t’,names=[‘label’,‘content’])

sep : str, default ‘,’

指定分隔符。如果不指定参数,则会尝试使用逗号分隔。分隔符长于一个字符并且不是‘\s+’,将使用python的语法分析器。并且忽略数据中的逗号。正则表达式例子:’\r\t’

names : array-like, default None

用于结果的列名列表,如果数据文件中没有列标题行,就需要执行header=None。默认列表中不能出现重复,除非设定参数mangle_dupe_cols=True。

数据的导入和观察

.shape,.head(),.tail(),.info(),.describe()

shape

返回数据集的大小,即行数×列数。

观察shape的目的仅为对数据有个初步的了解,知道其大概的大小,以方便后续研究。

head(),tail()

目的:对于数据首尾各阅读五条(默认),对数据进行一个简略的观察。

方式:函数返回

分析:通过观察数据的列名以及其他信息,对数据包含的元素进行分析。

info()

目的:通过info的返回值可以直观的了解数据每一列的情况,包括名称、类型、有多少空值。

方式:函数返回

分析:熟悉名称、类型、空值

describe()

目的:对相关统计量进行初步了解。

方式:函数返回

分析:describe()会返回相关统计量,包含个数count、平均值mean、方差std、最小值min、中位数25% 50% 75% 、以及最大值 看这个信息主要是瞬间掌握数据的大概的范围以及每个值的异常值的判断,比如有的时候会发现999 9999 -1 等值这些其实都是nan的另外一种表达方式

注意lightgbm算法好像很好用以后重点学习

决策树模型的lightgbm模型

传统的boosting算法(如GBDT和XGBoost)已经有相当好的效率,但是在如今的大样本和高维度的环境下,传统的boosting似乎在效率和可扩展性上不能满足现在的需求了,主要的原因就是传统的boosting算法需要对每一个特征都要扫描所有的样本点来选择最好的切分点,这是非常的耗时。为了解决这种在大样本高纬度数据的环境下耗时的问题,Lightgbm使用了如下两种解决办法:一是GOSS(Gradient-based One-Side Sampling, 基于梯度的单边采样),不是使用所用的样本点来计算梯度,而是对样本进行采样来计算梯度;二是EFB(Exclusive Feature Bundling, 互斥特征捆绑) ,这里不是使用所有的特征来进行扫描获得最佳的切分点,而是将某些特征进行捆绑在一起来降低特征的维度,是寻找最佳切分点的消耗减少。这样大大的降低的处理样本的时间复杂度,但在精度上,通过大量的实验证明,在某些数据集上使用Lightgbm并不损失精度,甚至有时还会提升精度。

根据人民网观点频道中的数据 此次的项目对短文本进行标题分类采用深度学习中的卷积神经网络(CNN)和循环神经网络中的长短时记忆模型(LSTM)组合起来,捕捉短文本表达的语义,对短文本自动文本分类进行智能化实现,为新闻网站的新闻分类实现提供参考。

采用了随机梯度下降、在线被动攻击算法、线性支持向量分类、岭回归和梯度提升5种分类算法,集成构成模型。

import os   #import os是指导入os模块到当前程序,利用它的API
from multiprocessing import cpu_count #multiprocessing包是Python中的多进程管理包,这句为了统计cpu个数
import numpy as np#NumPy函数库是Python开发环境的一个独立模块,是Python的一种开源的数值计算扩展工具
import shutil# os模块提供了对目录或者文件的新建/删除/查看文件属性,还提供了对文件以及目录的路径操作。比如说:绝对路径,父目录……  但是,os文件的操作还应该包含移动 复制  打包 压缩 解压等操作,这些os模块都没有提供。  而本章所讲的shutil则就是对os中文件操作的补充。--移动 复制  打包 压缩 解压,
import paddle#PaddlePaddle是一个开源的深度学习平台,而在我们进行使用的时候主要使用的是其核心框架Paddle Fluid。
import paddle.fluid as fluid#Paddle Fluid提供覆盖深度学习开发、训练、预测及部署全流程的服务。

接下来数据预处理生成数据字典

# 查看当前挂载的数据集目录, 该目录下的变更重启环境后会自动还原
# View dataset directory. This directory will be recovered automatically after resetting environment. 
!ls /home/aistudio/data
# 查看工作区文件, 该目录下的变更将会持久保存. 请及时清理不必要的文件, 避免加载过慢.
# View personal work directory. All changes under this directory will be kept even after reset. Please clean unnecessary files in time to speed up environment loading.
!ls /home/aistudio/work
import os
import numpy as np
import paddle
import paddle.fluid as fluid
from multiprocessing import cpu_count
class classify():
  data_root_path=""
  dict_path = "data/data9045/dict.txt"
    test_data_path = "data/data9045/Test_IDs.txt"
    model_save_dir = "work/model_bilstm/"#将语料中用到的词对应的向量加载到内存中
  # 获取字典长度
    def get_dict_len(d_path):
        with open(d_path, 'r', encoding='utf-8') as f:
            line = eval(f.readlines()[0])#eval返回传入字符串的表达式的结果,
            '''readlines() 之间的差异是后者一次读取整个文件,象 .read() 一样。.readlines() 自动将文件内容分析成一个行的列表,该列表可以由 Python 的 for ... in ... 结构进行处理'''
        return len(line.keys())
 # 1、创建train reader 和 test_reader
    def data_mapper(sample):
        data, label = sample
        data = [int(data) for data in data.split(',')]
        return data, int(label)
 # 创建数据读取器train_reader
    def train_reader(train_data_path):
        def reader():
            with open(train_data_path, 'r') as f:
                lines = f.readlines()
                # 打乱数据
                np.random.shuffle(lines)
                for line in lines:
                    data, label = line.split('\t')#Python split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串,num -- 分割次数。默认为 -1, 即分隔所有
                    yield data, label
        return paddle.reader.xmap_readers(classify.data_mapper, reader, cpu_count(), 1024)
#  创建数据读取器val_reader
    def val_reader(val_data_path):
        def reader():
            with open(val_data_path, 'r') as f:
                lines = f.readlines()
                # 打乱
                np.random.shuffle(lines)
                for line in lines:
                    data, label = line.split('\t')
                    yield data, label
        return paddle.reader.xmap_readers(classify.data_mapper, reader, cpu_count(), 1024)
    def test_reader(test_data_path):
        def reader():
            with open(test_data_path, 'r') as f:
                lines = f.readlines()
                # 打乱
                np.random.shuffle(lines)
                for line in lines:
                    data = line
                    yield data.strip(), -1
        return paddle.reader.xmap_readers(classify.data_mapper, reader, cpu_count(), 1024)
# 创建bi-lstm网络
    def bilstm_net(data,
                   dict_dim,
                   class_dim=14,
                   emb_dim=128,
                   hid_dim=128,
                   hid_dim2=96,
                    ):
        """
        理解bilstm要理解循环神经网络(RNN),LSTM是RNN的一个变种。对许多任务来说,使用LSTM比标准的RNN效果要好很多。几乎所有激动人心的结果都是在基于这种类型的RNN上实现的。lstm 的优点在于可以自主学习解决长距离依赖问题,即随着距离的增大。RNN越来越难将这种长距离的信息利用起来。 
        Bi-Lstm net
        除了在层次上进行改善网络结构,考虑方向是另一个进行改进的方向,毕竟之前LSTM网络是单向地处理序列信息,所以有些时候考虑文本后面地消息可能会提高模型地效果,就像是在进行单词推断地时候,也许文本后面地内容也会对单词地的推测有所帮助,所以,双向LSTM网络被提出,他是在两个方向地 LSTM 结构的组合
        """
 def CNN_net(data, dict_dim, class_dim=14, emb_dim=128, hid_dim=128, hid_dim2=98):
        emb = fluid.layers.embedding(input=data,
                                     size=[dict_dim, emb_dim])
        conv_3 = fluid.nets.sequence_conv_pool(
            input=emb,
            num_filters=hid_dim,
            filter_size=3,
            act="tanh",
            pool_type="sqrt")
        conv_4 = fluid.nets.sequence_conv_pool(
            input=emb,
            num_filters=hid_dim2,
            filter_size=4,
            act="tanh",
            pool_type="sqrt")
        output = fluid.layers.fc(
            input=[conv_3,conv_4], size=class_dim, act='softmax')
        return output
def ernie_base_net(class_dim,hid_dim=128):
        """
        Ernie base net
        教程详见https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%E8%BF%81%E7%A7%BB%E6%95%99%E7%A8%8B
        """
        module = hub.Module(name="ernie")
        inputs, outputs, program = module.context(trainable="True", max_seq_len=128)
        #pooled_output:句子粒度特征,对应的shape为[batch_size, hidden_size],可用于句子分类或句对分类任务。
        pooled_output = outputs["pooled_output"]
        cls_feats = fluid.layers.dropout(
            x=pooled_output,
            dropout_prob=0.1,
            dropout_implementation="upscale_in_train")
        logits = fluid.layers.fc(
            input=cls_feats,
            size=class_dim,
            param_attr=fluid.ParamAttr(
                name="cls_out_w",
                initializer=fluid.initializer.TruncatedNormal(scale=0.02)),
            bias_attr=fluid.ParamAttr(
                name="cls_out_b", initializer=fluid.initializer.Constant(0.)))
        output = fluid.layers.fc(
            input=logits, size=class_dim, act='softmax')
        return output
    def ernie_bilstm_net(class_dim, hid_dim=128):
        """
        Ernie bilstm net
        教程详见https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%E8%BF%81%E7%A7%BB%E6%95%99%E7%A8%8B
        """
        module = hub.Module(name="ernie")
        inputs, outputs, program = module.context(trainable="True", max_seq_len=128)
        #sequence_output:词粒度的特征,对应的shape为[batch_size, max_seq_len, hidden_size], 可用于序列标注任务。
        sequence_output = outputs["sequence_output"]
        fc0 = fluid.layers.fc(input=sequence_output, size=hid_dim * 4)
        rfc0 = fluid.layers.fc(input=sequence_output, size=hid_dim * 4)
        lstm_h, c = fluid.layers.dynamic_lstm(
            input=fc0, size=hid_dim * 4, is_reverse=False)
        rlstm_h, c = fluid.layers.dynamic_lstm(
            input=rfc0, size=hid_dim * 4, is_reverse=True)
        # extract last layer
        lstm_last = fluid.layers.sequence_last_step(input=lstm_h)
        rlstm_last = fluid.layers.sequence_last_step(input=rlstm_h)
        # concat layer
        lstm_concat = fluid.layers.concat(input=[lstm_last, rlstm_last], axis=1)
        # full connect layer
        output = fluid.layers.fc(
            input=lstm_concat, size=class_dim, act='softmax')
        return output
    def train(self,model_name):
        if model_name not in ['ernie','bilstm','cnn']:
            print ('  model_name must be in [ ernie / bilstm / cnn], 其中ernie仅提供使用思路')
            return 0
        # 获取训练数据读取器和测试数据读取器
        train_reader = paddle.batch(reader=self.train_reader(os.path.join(self.data_root_path, "data/data9045/shuffle_Train_IDs.txt")), batch_size=128)
        val_reader = paddle.batch(reader=self.val_reader(os.path.join(self.data_root_path, "data/data9045/Val_IDs.txt")), batch_size=128)
        # 定义输入数据, lod_level不为0指定输入数据为序列数据
        words = fluid.layers.data(name='words', shape=[1], dtype='int64', lod_level=1)
        label = fluid.layers.data(name='label', shape=[1], dtype='int64')
        dict_dim = self.get_dict_len(self.dict_path)
        # 获取分类器
        if model_name == 'bilstm':
            model =self.bilstm_net(words,dict_dim)
        if model_name=='cnn':
            model = self.CNN_net(words,dict_dim)
        if model_name == 'ernie':
            model = self.ernie_base_net(14)
            #model = self.ernie_bilstm_net(14,128)
        # 获取损失函数和准确率
        cost = fluid.layers.cross_entropy(input=model, label=label)
        avg_cost = fluid.layers.mean(cost)
        acc = fluid.layers.accuracy(input=model, label=label)
        # 获取预测程序
        val_program = fluid.default_main_program().clone(for_test=True)
        test_program = fluid.default_main_program().clone(for_test=True)
        # 定义优化方法
        optimizer = fluid.optimizer.AdagradOptimizer(learning_rate=0.08)
        opt = optimizer.minimize(avg_cost)
        # 创建一个执行器,CPU训练速度比较慢,此处选择gpu还是cpu
        #place = fluid.CPUPlace()
        place = fluid.CUDAPlace(0)
        exe = fluid.Executor(place)
        # 进行参数初始化
        exe.run(fluid.default_startup_program())
        # 定义数据映射器
        feeder = fluid.DataFeeder(place=place, feed_list=[words, label])
        EPOCH_NUM =4
        # 开始训练
        for pass_id in range(EPOCH_NUM):
            # 进行训练
            for batch_id, data in enumerate(train_reader()):
                train_cost, train_acc = exe.run(program=fluid.default_main_program(),
                                                feed=feeder.feed(data),
                                                fetch_list=[avg_cost, acc ])
                if batch_id % 200 == 0:
                    print('Pass:%d, Batch:%d, Cost:%0.5f, Acc:%0.5f' % (pass_id, batch_id, train_cost[0], train_acc[0]))
                    # 进行测试
                    val_costs = []
                    val_accs = []
                    for batch_id, data in enumerate(val_reader()):
                        val_cost, val_acc = exe.run(program=val_program,
                                                      feed=feeder.feed(data),
                                                      fetch_list=[avg_cost, acc])
                        val_costs.append(val_cost[0])
                        val_accs.append(val_acc[0])
            # 计算每个epoch平均预测损失在和准确率
            val_cost = (sum(val_costs) / len(val_costs))
            val_acc = (sum(val_accs) / len(val_accs))
            print('Test:%d, Cost:%0.5f, ACC:%0.5f' % (pass_id, val_cost, val_acc))
            # 保存预测模型
            if not os.path.exists(self.model_save_dir):
                os.makedirs(self.model_save_dir)
            fluid.io.save_inference_model(self.model_save_dir,
                                        feeded_var_names=[words.name],
                                        target_vars=[model],
                                        executor=exe)
        print('训练模型保存完成!')
        self.test(self)
        print('测试输出已生成!')
    # 获取数据
    def get_data(self,sentence):
        # 读取数据字典
        with open(self.dict_path, 'r', encoding='utf-8') as f_data:
            dict_txt = eval(f_data.readlines()[0])
        dict_txt = dict(dict_txt)
        # 把字符串数据转换成列表数据
        keys = dict_txt.keys()
        data = []
        for s in sentence:
            # 判断是否存在未知字符
            if not s in keys:
                s = '<unk>'
            data.append(int(dict_txt[s]))
        return data
    def test(self):
        data = []
        # 获取预测数据
        with open(self.test_data_path, 'r', encoding='utf-8') as test_data:
            lines = test_data.readlines()
        for line in lines:
            tmp_sents = []
            for word in line.strip().split(','):
                tmp_sents.append(int(word))
            data.append(tmp_sents)
        def load_tensor(data):
            # 获取每句话的单词数量
            base_shape = [[len(c) for c in data]]
            # 创建一个执行器,CPU训练速度比较慢
            #place = fluid.CPUPlace()
            place = fluid.CUDAPlace(0)
            # 生成预测数据
            tensor_words = fluid.create_lod_tensor(data, base_shape, place)
            #infer_place = fluid.CPUPlace()
            infer_place = fluid.CUDAPlace(0)
            # 执行预测
            infer_exe = fluid.Executor(infer_place)
            # 进行参数初始化
            infer_exe.run(fluid.default_startup_program())
            # 从模型中获取预测程序、输入数据名称列表、分类器
            print('loading model')
            [infer_program, feeded_var_names, target_var] = fluid.io.load_inference_model(dirname=self.model_save_dir, executor=infer_exe)
            result=[]
            result = infer_exe.run(program=infer_program,
                                 feed={feeded_var_names[0]: tensor_words},
                                 fetch_list=target_var)
            names = ["财经", "彩票", "房产", "股票", "家居", "教育", "科技",
                     "社会", "时尚", "时政", "体育", "星座", "游戏", "娱乐"]
            # 输出结果
            print('writting')
            for i in range(len(data)):
            #for i in range(83599):
                lab = np.argsort(result)[0][i][-1]
                #print('预测结果标签为:%d, 名称为:%s, 概率为:%f' % (lab, names[lab], result[0][i][lab]))
                with open(self.save_path, 'a', encoding='utf-8') as ans:
                    #print (names[lab])
                    ans.write( names[lab]+"\n")
            ans.close()
        print('loading 1/4 data')
        load_tensor(data[:int(83599/4)])
        print('loading 2/4 data')
        load_tensor(data[int(83599/4):2*int(83599/4)])
        print('loading 3/4 data')
        load_tensor(data[2*int(83599/4):3*int(83599/4)])
        print('loading 4/4 data')
        load_tensor(data[3*int(83599/4):])
        print('测试输出已生成!')
if __name__ == "__main__":
    classify.train(classify,'bilstm')
    #classify.train(classify,'cnn')
    #classify.train(classify,'ernie')

本人已经很认真的去理解学姐的代码和思路,但是实在是学校课程学的少,现在读起来太困难了,读了两遍头发哗哗的掉啊,啊这,大家自行去飞桨上看学姐的代码吧

附上链接

https://aistudio.baidu.com/bdcpu3/user/694562/1761950/notebooks/1761950.ipynb

如果大家想看简易版的就进入我的博客看另一篇文章,是我们小组到最后确定的方案,比较好读容易理解,希望和大家一起进步,一起学习,从一个小白到一个非常厉害的大佬,希望大家能够点赞评论支持一下


相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
1月前
|
机器学习/深度学习 数据采集 数据可视化
Python数据科学实战:从Pandas到机器学习
Python数据科学实战:从Pandas到机器学习
|
29天前
|
机器学习/深度学习 数据可视化 数据处理
掌握Python数据科学基础——从数据处理到机器学习
掌握Python数据科学基础——从数据处理到机器学习
41 0
|
29天前
|
机器学习/深度学习 数据采集 人工智能
机器学习入门:Python与scikit-learn实战
机器学习入门:Python与scikit-learn实战
38 0
|
1月前
|
机器学习/深度学习 数据采集 数据挖掘
Python在数据科学中的应用:从数据处理到模型训练
Python在数据科学中的应用:从数据处理到模型训练
|
17天前
|
人工智能 数据可视化 数据挖掘
探索Python编程:从基础到高级
在这篇文章中,我们将一起深入探索Python编程的世界。无论你是初学者还是有经验的程序员,都可以从中获得新的知识和技能。我们将从Python的基础语法开始,然后逐步过渡到更复杂的主题,如面向对象编程、异常处理和模块使用。最后,我们将通过一些实际的代码示例,来展示如何应用这些知识解决实际问题。让我们一起开启Python编程的旅程吧!
|
16天前
|
存储 数据采集 人工智能
Python编程入门:从零基础到实战应用
本文是一篇面向初学者的Python编程教程,旨在帮助读者从零开始学习Python编程语言。文章首先介绍了Python的基本概念和特点,然后通过一个简单的例子展示了如何编写Python代码。接下来,文章详细介绍了Python的数据类型、变量、运算符、控制结构、函数等基本语法知识。最后,文章通过一个实战项目——制作一个简单的计算器程序,帮助读者巩固所学知识并提高编程技能。
|
4天前
|
Unix Linux 程序员
[oeasy]python053_学编程为什么从hello_world_开始
视频介绍了“Hello World”程序的由来及其在编程中的重要性。从贝尔实验室诞生的Unix系统和C语言说起,讲述了“Hello World”作为经典示例的起源和流传过程。文章还探讨了C语言对其他编程语言的影响,以及它在系统编程中的地位。最后总结了“Hello World”、print、小括号和双引号等编程概念的来源。
98 80
|
22天前
|
存储 索引 Python
Python编程数据结构的深入理解
深入理解 Python 中的数据结构是提高编程能力的重要途径。通过合理选择和使用数据结构,可以提高程序的效率和质量
134 59
|
2天前
|
分布式计算 大数据 数据处理
技术评测:MaxCompute MaxFrame——阿里云自研分布式计算框架的Python编程接口
随着大数据和人工智能技术的发展,数据处理的需求日益增长。阿里云推出的MaxCompute MaxFrame(简称“MaxFrame”)是一个专为Python开发者设计的分布式计算框架,它不仅支持Python编程接口,还能直接利用MaxCompute的云原生大数据计算资源和服务。本文将通过一系列最佳实践测评,探讨MaxFrame在分布式Pandas处理以及大语言模型数据处理场景中的表现,并分析其在实际工作中的应用潜力。
16 2
|
16天前
|
小程序 开发者 Python
探索Python编程:从基础到实战
本文将引导你走进Python编程的世界,从基础语法开始,逐步深入到实战项目。我们将一起探讨如何在编程中发挥创意,解决问题,并分享一些实用的技巧和心得。无论你是编程新手还是有一定经验的开发者,这篇文章都将为你提供有价值的参考。让我们一起开启Python编程的探索之旅吧!
41 10
下一篇
DataWorks