Task1-数据探索分析

数据存储

由于用pandas一次性读取20w条数据显示memoryerror,内存不够,所以想到把数据存到数据库中,随用随取比较简便。把训练集20w条数据存到了mongodb数据库中。

import pandas as pd
import pymongodf = pd.read_csv(r'D:\Datawhale学习资料\15期-NLP新闻文本分类\data\train_set.csv', sep='\t')
texts_num = len(df.index)  # 计算出新闻文本的总数量
print(df.columns)  # 读取到训练集的列名['label','text']texts_arr = []
for i in range(texts_num):dict1 = dict()dict1['label'] = int(df.iloc[i, 0])dict1['text'] = str(df.iloc[i, 1])texts_arr.append(dict1)
print(len(texts_arr))  # 验证arr的准确性
# print(texts_arr[:5])# 建立mongodb数据库
client = pymongo.MongoClient('localhost', 27017)
db = client['newsTextClassification']
table = db['train_set']table.insert(texts_arr)
print(table.find().count())
# 关闭连接
client.close()

mongodb的数据操作详见资料,这里使用insert函数一次性把20w条数据添加到集合train_set中,注意texts_arr是列表,元素是字典型数据。

数据探索

新闻类别分布

统计新闻文本类别的分布,探究数据集的均衡性:

labels_iterator = table.find({}, {'label': 1, '_id': 0})
labels = map(lambda x: int(x['label']), labels_iterator)
labels_series = pd.Series(list(labels))
# print(texts_series.describe())  # 输出describe信息
label_counts = labels_series.groupby(labels_series.values).count()  # 对series对象进行分组统计

技术知识:

  1. mongodb数据库的find()函数,1)第一个参数是“where”,第二个参数是显示哪些标签,注意除了“_id”,剩下的标签不能是相反的数值。2)本例中返回的是游标对象Cursor,是迭代器,元素是字典型数据。
  2. map()函数生成的对象是map对象,为迭代器。
  3. describe()函数针对的是Series对象和DataFrame对象,np.array数组没有describe()函数;
  4. Series对象的groupby()函数,参数需要指定为Series对象的数值

并结合pyecharts库可视化展现类别分布情况:

from pyecharts.charts import Bar, Line
from pyecharts import options as opts
b = (Bar().add_xaxis(list(label_counts.index)).add_yaxis("新闻文本类别数量", list(map(lambda x: int(x), label_counts.values)), bar_width=20)# .set_series_opts(label_opts=opts.LabelOpts(is_show=False))# .set_global_opts(#     xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)),#     title_opts=opts.TitleOpts(title="Bar-旋转X轴标签", subtitle="解决标签名字过长的问题"),.render("label_counts_graph.html")
)

注意,pyecharts库更新后,采用一键式制作图表,详细内容见中文文档:


从上图的统计结果可以看到,第0、1、2类占了大部分,这就很容易对这三类的数据过拟合,而其他类会欠拟合,是一个典型的非均衡数据集,在后续模型训练中需要考虑分类标签的权重,或者训练时采用分层抽样的方法,进行K折交叉验证,以最大程度消除局部标签过拟合的问题。

新闻文本长度(字符数目)分布

# 统计新闻文本长度分布
texts_iterator = table.find({}, {'text': 1, '_id': 0})
texts_length = map(lambda x: len(x['text'].split(' ')), texts_iterator)
texts_series = pd.Series(list(texts_length))
# print(texts_series.describe())  # 输出describe信息
length_counts = texts_series.groupby(texts_series.values).count()  # 对series对象进行分组统计


知识:

  1. 有超长文本(5万字符以上),但这部分数据很少,所以可以通过截取的方法来进行处理。
  2. 中位数是676个字符,平均数是907个字符;但这是未处理过的文本长度,处理后会进一步缩减(几百个字符实在太多了,BERT最多才能处理512个字符的长度,所以要经过去停留词、去高频词等方法来减少字符)。

并结合pyecharts库制作条形图和文本数目累计占比折线图,为后续构建td-idf和词向量事设置max_feature参数提供参考:

可以看到95%以上的新闻文本长度都在3000词以内,所以大致可以限制在3000以内(在处理高频词和低频词等停用词后再进行统计会更精准)

统计每类新闻中出现最多的字符(作业2)

标点符号筛选

由于对新闻文本做了匿名处理,无法直接判断出标点符号等停用词,只能通过高文本覆盖率来筛选出可能是标点符号的字符。
Tips:对于本项目的停用词来说,应包含两部分,一是高覆盖率的字符,二是超低频次的字符,前者主要指标点符号,后者主要指无价值字符。
所以在统计出现最多的字符之前,先筛选出高覆盖率的字符,这里覆盖率从80%~100%依次进行探索:

from collection import Counter
texts_iterator = table.find({}, {'text': 1, '_id': 0})
texts_unique = list(map(lambda x: ' '.join(list(set(x['text'].split(' ')))), texts_iterator))
unique_allines = ' '.join(texts_unique)
word_count = Counter(unique_allines.split(' '))
# print(len(word_count))  # 共有6869个不重复字符
word_count = sorted(word_count.items(), key=lambda d: int(d[1]), reverse=True)
example = range(80, 100)
dict1 = {}
for i in example:stopwords = []for word in word_count:if word[1] >= int(0.01 * i * 200000):stopwords.append(word[0])else:breakdict1['{}%'.format(i)] = len(stopwords)

技术知识:

  1. set()函数可以直接去重得到无重复的元素集合。
  2. Count()函数返回的是Counter对象,类似于字典型数据。详细内容见资料:
  3. sorted()函数的参数设置详细见资料:

并结合pyecharts库制作折线变化图:

index = [x for x in dict1.keys()]
num = [x for x in dict1.values()]
line2 = (Line().add_xaxis(index).add_yaxis(series_name="字符个数与文本覆盖率的关系",y_axis=num,label_opts=opts.LabelOpts(is_show=False),).set_global_opts(xaxis_opts=opts.AxisOpts(type_="category"),yaxis_opts=opts.AxisOpts(name='字符个数', type_='value'))
)


可以看到覆盖率在90%以上时只有2~3个字符,并且保持了比较高的平稳性,所以选择超过90%覆盖率的这三个字符作为标点符号,分别是‘3750’、‘900’、‘648’。
知识点:其实筛选标点符号,不能只关注文本覆盖率,也要关注频次,即采用tf-idf的方法衡量字符的重要性,从重要性的角度来筛选标点符号

统计字符数目

def mostcommon_cate(cate):iterator = table.find({'label': cate})texts_cate = map(lambda x: x['text'], iterator)texts_str = ' '.join(list(texts_cate)).replace(' 3750', '').replace(' 900', '').replace(' 648', '')  # 去掉停用词mostcommon_word = Counter(texts_str.split(' ')).most_common(1)return cate, mostcommon_wordindex = [int(x) for x in np.arange(14)]  # 这里需要进行强制转换类型,将numpy.int64转变成int型,因为pymongo读取不能读取numpy对象
result = map(mostcommon_cate, index)
for i in result:print(i[0], i[1][0])

得到结果如下:

统计新闻文本句子数量分布(作业1)

根据假定的标点符号(通过作业2中的覆盖率探索,也可以判断出假定的三个标点符号具有较高的准确度),对新闻文本进行分割:

texts_iterator = table.find({}, {'text': 1, '_id': 0})  # 疑问:为什么当这里用上面的texts_iterator就取不到数了?
texts_map = map(lambda x: x['text'], texts_iterator)# 假定字符3750、900、648是标点符号
def sentence_count(text_str):sentence_list = re.split(' 3750 | 900 | 648 ', text_str)count = len(sentence_list)return countsentence_counts = list(map(sentence_count, texts_map))
sentence_count_series = pd.Series(sentence_counts)
print(sentence_count_series.describe())
sentence_counts_distru = sentence_count_series.groupby(sentence_count_series.values).count()

技术知识:

  1. 从mongodb数据库中采用find()函数取出数据后,得到的是Cursor迭代器对象,如果对Cursor进行操作后,在后续二次操作时,需要重新取数,否则数据为0??
  2. 单纯的str.split()函数中,只能有1个分割符号,所以采用re.split()函数,用‘|’把多个分隔符号隔开即可。

并结合pyecharts库进行可视化:

可以看到98%左右的新闻文本句子数目都在300以内。

Task 2 基于机器学习的文本分类

1 文本向量化

首先从mongodb数据库中读取出20w条训练数据集,采用TfidfVectorizer对文档进行向量化表示,代码如下:

client = pymongo.MongoClient('localhost', 27017)
db = client['newsTextClassification']
table = db['train_set']
data_all = table.find({}, {"_id": 0})
data_df = pd.DataFrame(data_all)
X_data = data_df.text
tf_idf = TfidfVectorizer(ngram_range=(1, 3), max_features=2000)
X = tf_idf.fit_transform(X_data)

注意返回的X是一个稀疏矩阵,在后续训练集拆分时需要用X.toarray()转换为数组来运算。

为了防止每次tfidf向量化耗费大量时间,将训练好的tfidf模型保存在本地,采用pickle方法:

# 把训练好的tfidf保存到本地
with open('tfidf_word.pkl', 'wb') as f:pickle.dump(X, f)
# 把本地保存的tfidf载入
X = pickle.load(open('tfidf_word.pkl', "rb"))

2 训练集拆分

这里使用了K折交叉验证的方法对训练集进行拆分,并且注意到训练集中的新闻文本是一个高度不均衡的数据集,所以在拆分时想要将训练集和验证集按照源文本中的类别比例划分,这里采用StratifiedKFold方法,来进行分层抽样:

# 训练集:验证集=4:1,并且进行5次模型训练
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
X = X.toarray()  # 注意需要强制转换一下
for train_index, verify_index in skf.split(X, y):X_train, y_train = X[train_index], y[train_index]X_verify, y_verify = X[verify_index], y[verify_index]

朴素贝叶斯文本分类

直接采用sklearn库中的多项式朴素贝叶斯模型进行文本分类:

from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import f1_scoreclf = MultinomialNB(fit_prior=True)
clf.fit(X_train, y_train)
val_pred = clf.predict(X_verify)
f1_res = f1_score(y_verify, val_pred, average='macro')

由此得到了f1值,因为做了K折交叉验证,所以要运行5次,最后得到f1的平均值。

结果如下:

五次的f1值分别为:0.831、0.833、0.828、0.829、0.833
平均f1值为0.831.

基于机器学习的新闻文本分类相关推荐

  1. 【项目实战课】NLP入门第1课,人人免费可学,基于TextCNN的新闻文本分类实战...

    欢迎大家来到我们的项目实战课,本期内容是<基于TextCNN的新闻文本分类实战>. 所谓项目课,就是以简单的原理回顾+详细的项目实战的模式,针对具体的某一个主题,进行代码级的实战讲解,可以 ...

  2. 自然语言处理(二)基于CNN的新闻文本分类

    自然语言处理(二) 1.Task1 数据集探索 1.1下载数据集 1.2数据集的描述 1.3 数据的预处理 1.4 CNN卷积神经网络 1.5 训练与验证 2.IMDB 2.1下载 IMDB 数据集 ...

  3. 基于BERT的新闻文本分类

    2017年Transformer模型横空出世,encoder-decoder的创新效果显著,2018年Google又提出了BERT预训练模型,可谓是大大推动了NLP的进步,关于transformer和 ...

  4. 基于 LSTM-Attention 的中文新闻文本分类

    1.摘 要 经典的 LSTM 分类模型,一种是利用 LSTM 最后时刻的输出作为高一级的表示,而另一种是将所有时刻的LSTM 输出求平均作为高一级的表示.这两种表示都存在一定的缺陷,第一种缺失了前面的 ...

  5. 基于朴素贝叶斯和LSTM的两种新闻文本分类方法

    新闻文本分类 文章目录 新闻文本分类 一.项目背景 二.数据处理与分析 三.基于机器学习的文本分类--朴素贝叶斯 1. 模型介绍 2. 代码结构 3. 结果分析 四.基于深度学习的文本分类--LSTM ...

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

    试题说明 试题说明 任务描述 基于THUCNews数据集的文本分类, THUCNews是根据新浪新闻RSS订阅频道2005~2011年间的历史数据筛选过滤生成,包含74万篇新闻文档,参赛者需要根据新闻 ...

  7. 【文本分类】基于BERT预训练模型的灾害推文分类方法、基于BERT和RNN的新闻文本分类对比

    ·阅读摘要: 两篇论文,第一篇发表于<图学学报>,<图学学报>是核心期刊:第二篇发表于<北京印刷学院学报>,<北京印刷学院学报>没有任何标签. ·参考文 ...

  8. 新闻文本分类之旅 机器学习

    天池-零基础入门NLP 新闻文本分类 导入相关库 读入数据 文本表示 训练模型 输出上传文件 存在问题 新闻文本分类 比赛地址 文本分类的任务是将给定的文本划分到事先规定的文本类别. 赛题难度: 匿名 ...

  9. 新闻文本分类--任务5 基于深度学习的文本分类2

    Task5 基于深度学习的文本分类2 在上一章节,我们通过FastText快速实现了基于深度学习的文本分类模型,但是这个模型并不是最优的.在本章我们将继续深入. 基于深度学习的文本分类 本章将继续学习 ...

最新文章

  1. 卡尔曼算法笔记---思想和实际应用物理含义的理解
  2. Vue-路由模式 hash 和 history
  3. 一张图看懂阿里云网络产品【十五】IPv6 解决方案
  4. c语言通讯录以及写入文件,学C三个月了,学了文件,用C语言写了个通讯录程序...
  5. c#3.0关于JSON简单操作的实用帮助类(泛型实现)
  6. java 加法 溢出_StackOverflow热帖:Java整数相加溢出怎么办?Java8一步搞定~
  7. 高效便捷地创建单元格数据图表
  8. 深度学习笔记(23) 卷积维度
  9. 深度之眼-科赛网二分类大赛入门之路
  10. 电容充放电原理图_HDI滤波电容FANOUT案例
  11. e的n次方要怎么用计算机计算,Excel函数公式大全,使用EXP函数计算常数e的n次方....
  12. 老男孩教育46期-丁温郝
  13. Wince6.0nbsp;s3c6410触摸屏驱动分析
  14. python3.8零基础入门教程_正版 Python 3.8编程快速入门 针对wan全零基础入门的读者 采用*小化安装+极简代码的教学...
  15. 做好产品需求文档的这十步
  16. Scroller简介
  17. php编程模块英文缩写_工作中常用的英文单词缩写
  18. Hadoop HDFS启动报异常:We expected txid 130043, but got txid 229381
  19. TB6612FNG与直流电机控制教程
  20. MySQL免安装版配置部署详细教程

热门文章

  1. 支付宝产品签约-“系统综合评估签约条件不满足”解决办法
  2. [编程入门]自定义函数求一元二次方程
  3. 笔记:for循环,物理知识煮鸡蛋
  4. asp+excel通用成绩查询系统 v6.8 工资查询物业费水电费查询通用哦
  5. 计算机专业产品开发译码,计算机专业前景可好
  6. ROM修改---修改CPU信息和GPU信息
  7. SWIFT是什么意思?
  8. 即时聊天表情功能的实现
  9. python3一键上网认证的图形化exe程序(下篇)
  10.  电子工程师的出路在哪里?干了两年电子工程师(硬件开发),不知道以后方向在哪里,挺迷茫!