天池新闻文本分类——数据读取与数据分析
目录
- 数据获取
- 数据分析过程
- 句子长度分布分析
-
新闻类型比例分析
-
字符频率统计分析
-
数据分析结果总结
-
作业
-
数据读取
赛题数据虽然属于文本数据类型,并且每条新闻的长度是不固定的,仍然采用CSV格式进行存储。因此,在实际操作中较为方便地通过Pandas库实现对数据的读取与解析过程。
import pandas as pd
train_df = pd.read_csv('data/train_set.csv', sep='\t', nrows=100)
pandas.read_csv由三个关键组成部分构成:
首先设定文件路径部分,在实际操作中建议根据实际需求设置合适的存储位置,默认情况下会从工作目录中读取数据;
其次定义分隔符参数sep,默认情况下会采用默认分隔方式处理数据字段;
最后指定读取行数nrows,在处理大规模数据时建议将此值设定在100以内以确保运行效率。

此页面展示了一组经过处理的数据样本。这些数据以表格形式呈现,并包含两条信息:一条标识文章类型(如科技新闻、社会新闻等),另一条记录每篇文章的相关字符信息(如摘要长度)。
数据分析
在本次操作中, 我们获取了全部的训练集数据, 并在此过程中运用数据分析手段试图获得以下几点结论
在赛题数据中,请问新闻文本的数量是多少?
请问在整体结构上各类别所占的比例如何?哪些类别在整体中占比较大?
请问赛题数据中的字符频率如何分布?
句子长度分析
在赛题的数据集中,每一行句子中的字符通过空格分隔开。因此可以通过计算每个句子所包含的单词数量来确定其长度。统计结果如下:
train_df['text_len'] = train_df['text'].apply(lambda x: len(x.split(' ')))
print(train_df['text_len'].describe())
输出结果为

通过对新闻类句子的数量统计可以看出,在本次赛题中提供的文本整体较为冗长。具体而言,在所分析的所有新闻类句子里均值每个句子里包含了907个字符;其中最简短的一个句子里仅包含2个字符;而最长的一个句子里则包含了57,921个字符
下图将句子长度绘制了直方图,可见大部分句子的长度都几种在2000以内。
import matplotlib.pyplot as plt
_ = plt.hist(train_df['text_len'], bins=200)
plt.xlabel('Text char count')
plt.title("Histogram of char count")

import numpy as np
import seaborn as sns
def split_df(df_row):
return len(str(df_row).split())
len_dist = np.vectorize(split_df)(train_df['text'])
plt.figure(figsize=(15,5))
len_dist = np.vectorize(split_df)(train_df['text'])
ax = sns.distplot(len_dist, bins=100)
ax.set_xlim([0,max(len_dist)])
ax.set_xlabel("length of sample")
ax.set_ylabel("prob of sample")

新闻类别分布
下一步可以对数据集进行类别分布统计,并详细计算每类新闻的具体样本数量
train_df['label'].value_counts().plot(kind='bar')
plt.title('News class count')
plt.xlabel("category")

在数据集里各标签之间的对应关系具体如下:{‘科技’→0,…} 其中包含股票、体育、娱乐等多个类别……一直到星座对应的编号为13
通过统计结果可以看出,在本次比赛中各参赛作品的创新性分布情况上存在明显不均衡的现象。具体而言,在参赛作品数量最多的领域中属于科技创新领域的创新作品占比最高,在数量次之的领域中则以金融市场的相关分析居多,在数量最少的领域中则是涉及天文学研究的内容最少。
字符分布统计
首先计算每个字符在训练集中的出现频率;然后将所有句子连在一起,并按顺序分割出每一个单独的字符,并记录它们的数量
from collections import Counter
all_lines = ' '.join(list(train_df['text']))
word_count = Counter(all_lines.split(" "))
word_count = sorted(word_count.items(), key=lambda d:d[1], reverse = True)
print(len(word_count))
# 6869
print(word_count[0])
# ('3750', 7482224)
print(word_count[-1])
# ('3133', 1)

根据统计数据显示,在训练集中共有6869个汉字;其中编码为③七五〇号字符出现频率最高;而编码为〇千三百一十三号字符则出现频率最低。
数据分析的结论
通过上述分析我们可以得出以下结论:
赛题中每条新闻平均包含一千个字符,在此过程中部分条目还呈现出较长的特征;从各类别数据分布来看,在本题目中科技相关的主题内容占据了较大比重(约达4,000件),而天文学相关的小号类新闻数量仅约一千条;整个赛题共计包含了7,567至8,321个字符;通过数据分析方法的应用我们还能进一步获得以下结论:
每个新闻平均字符个数较多,可能需要截断;
由于类别不均衡,会严重影响模型的精度;
作业
假设以字符3750为基准,请探讨一下赛题中平均每篇新闻通常包含多少个这样的标点符号900和648。
#参考https://superlova.github.io/2020/07/22/%E3%80%90%E7%AB%9E%E8%B5%9B%E6%89%93%E5%8D%A1%E3%80%91%E9%9B%B6%E5%9F%BA%E7%A1%80%E5%85%A5%E9%97%A8NLP%E4%B9%8B%E6%96%B0%E9%97%BB%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%E4%B9%8B%E6%95%B0%E6%8D%AE%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%88%86%E6%9E%90/
def sum_of_sep(row):
counter = Counter(row.split())
return counter.get('3750', 0)+counter.get('900', 0)+counter.get('648', 0)
sum_sep = np.vectorize(sum_of_sep)(train_df['text'])
np.round(np.mean(sum_sep+1))
79.0
2、统计每类新闻中出现次数对多的字符
word_count_dict = {}
for name, df in train_df.groupby('label'):
# print(name, type(df))
all_text = ' '.join(list(df['text'].apply(lambda x: ' '.join(list(x.split(' '))))))
word_count_single_class = Counter(all_text.split(" "))
word_count_single_class = sorted(word_count_single_class.items(), key=lambda d:int(d[1]), reverse = True)
word_count_dict[name] = word_count_single_class
# 查看每个类别出现最多的词汇
for label in range(14):
print(index_2_label_dict[label], word_count_dict[label][0])
科技 (‘3750’, 1267331)
股票 (‘3750’, 1200686)
体育 (‘3750’, 1458331)
娱乐 (‘3750’, 774668)
时政 (‘3750’, 360839)
社会 (‘3750’, 715740)
教育 (‘3750’, 469540)
财经 (‘3750’, 428638)
家居 (‘3750’, 242367)
游戏 (‘3750’, 178783)
房产 (‘3750’, 180259)
时尚 (‘3750’, 83834)
彩票 (‘3750’, 87412)
星座 (‘3750’, 33796)
查看TOP10
for label in range(14):
print(index_2_label_dict[label], [x for x,_ in word_count_dict[label][:10]])
