当前位置: 代码迷 >> 综合 >> Datawhale零基础入门NLP-Task2 数据读取与数据分析
  详细解决方案

Datawhale零基础入门NLP-Task2 数据读取与数据分析

热度:16   发布时间:2024-01-31 03:34:24.0

本文将对新闻文本分类大赛数据进行读取和初步分析

数据读取

分别读取训练集与测试集:

data_train = pd.read_csv("train_set.csv",sep='\t')
data_test = pd.read_csv("test_a.csv")

这里pandas.read_csv()有很多参数,以下列举部分常用的并作简要解释:

  • sep: str, default ‘,’

    指定分隔符。如果不指定参数,则会尝试使用逗号分隔。分隔符长于一个字符并且不是‘\s+’,将使用python的语法分析器。并且忽略数据中的逗号。正则表达式例子:’\r\t’,’\s+’->匹配任何空白字符,包括空格、制表符、换页符等等

  • delimiter : str, default None
    备用分隔符(如果指定该参数,则sep参数失效)

  • names: 设定列标题(前面分隔后会分成几列)

  • skiprows: list-like or interger, default None

    需要忽略的行数,就是从第多少行开始读起

  • skip_blank_lines: boolean, default True

    跳过空白行, 如果false,记为NaN

  • parse_dates : boolean or list of ints or names or list of lists or dict, default False

    boolean. True -> 解析索引
    list of ints or names. e.g. If [1, 2, 3] -> 解析1,2,3列的值作为独立的日期列;
    list of lists. e.g. If [[1, 3]] -> 合并1,3列作为一个日期列使用
    dict, e.g. {‘foo’ : [1, 3]} -> 将1,3列合并,并给合并后的列起名为”foo”

  • encoding : str, default None
    指定字符集类型,通常指定为’utf-8’. 在做Textmining的时候,有时候需要编码方式设为包容性更大的,比如’ISO8859-1’

  • nrows : int, default None
    需要读取的行数(从文件头开始算起)。有时候文件过大,可以只读前多少行做测试,节省时间。

之后可以打印少许数据查看数据集内容的结构。

print(data_train.head())
print(data_test.head())
label text
0 2 2967 6758 339 2021 1854 3731 4109 3792 4149 15…
1 11 4464 486 6352 5619 2465 4802 1452 3137 5778 54…
2 3 7346 4068 5074 3747 5681 6093 1777 2226 7354 6…
3 2 7159 948 4866 2109 5520 2490 211 3956 5520 549…
4 3 3646 3055 3055 2490 4659 6065 3370 5814 2465 5…
text
0 5399 3117 1070 4321 4568 2621 5466 3772 4516 2…
1 2491 4109 1757 7539 648 3695 3038 4490 23 7019…
2 2673 5076 6835 2835 5948 5677 3247 4124 2465 5…
3 4562 4893 2210 4761 3659 1324 2595 5949 4583 2…
4 4269 7134 2614 1724 4464 1324 3370 3370 2106 2…

可以发现训练集由文本类别与文本内容两列组成,而测试集只有一列文本,且所有的这些文本都被进行了匿名处理。

数据分析

句子长度分析

data_train['len'] = data_train['text'].apply(lambda x:len(x.split(' ')))
data_train['len'].describe()

这里使用str.split()来将文本分皆为元素为单个字符的列表,在求取列表的长度,即句子长度。之后用Series.describe()来获取这些长度数值的统计数据。

len
count 200000.000000
mean 907.207110
std 996.029036
min 2.000000
25% 374.000000
50% 676.000000
75% 1131.000000
max 57921.000000

由上面的表格可以看出,这200000个文本平均句长为907.2,最大句长为57921,最短为2,也就是最短的句子仅仅只有两个字符。再者通过一分位(25%)和三分位(75%)我们可以得出句长大部分集中在300-1200范围之间。这里我们可以用直方图来更直观的表现。

import seaborn as sns
%pylab inline
#import matplotlib.pyplot as plt
sns.distplot(data_train['len'],bins = 200)
plt.xlabel('Text char count')
plt.title("Histogram of char count")

在这里插入图片描述

上面代码里的pylab是ipython里的magic function。他其实相当于以下代码:

import numpy
import matplotlib
from matplotlib import pylab, mlab, pyplot
np = numpy
plt = pyplotfrom IPython.display import display
from IPython.core.pylabtools import figsize, getfigsfrom pylab import *
from numpy import *

详细见:https://ipython.org/ipython-doc/2/api/generated/IPython.core.magics.pylab.html

新闻类别分布

用Series.value_counts()来获得各个类别出现的次数,再用seaborn.barplot()可视化出来。

class_count = pd.DataFrame(data_train['label'].value_counts()).reset_index()
sns.barplot(x='index',y = 'label',data = class_count)
plt.title('News class count')
plt.ylabel("count")
plt.xlabel("category")

新闻类别分布

在数据集中标签的对应的关系如下:{‘科技’: 0, ‘股票’: 1, ‘体育’: 2, ‘娱乐’: 3, ‘时政’: 4, ‘社会’: 5, ‘教育’: 6, ‘财经’: 7, ‘家居’: 8, ‘游戏’: 9, ‘房产’: 10, ‘时尚’: 11, ‘彩票’: 12, ‘星座’: 13}

可以发现科技类别的新闻文本是最多的,其次是股票,星座类别的文本最少。并且各类别的分布明显的不均匀,但也基本符合实际情况

字符分布统计

from collections import Counter
#由于数据集过大,这里做了一下采样
data_train_sample = data_train.sample(n=10000,random_state=405633)
all_lines = ' '.join(list(data_train_sample['text']))
word_count = Counter(all_lines.split(" "))
word_count = sorted(word_count.items(), key=lambda d:d[1], reverse = True)
print(len(word_count))
print(word_count[0])
print(word_count[-1])

上述代码先使用str.join(list)合并所有文本,之后转化为字符列表后再用collections.Counter函数对字符出现次数进行统计,然后将其以字典形式输出,最后根据字符频率进行排序,输出元素为元组的列表。

5327
[('3750', 372984), ('648', 244868), ('900', 162333), ('3370', 105991), ('4464', 82099)]
('6315', 1)

从输出结果看,总共有5327个字符,然后‘3750’出现的最多,37万多,这个量级非常的大,平均下来每篇文档出现37.29次,这里很有可能是标点。

#利用set的无重复性滤除重复字符
data_train_sample['text_unique'] = data_train_sample['text'].apply(lambda x: ' '.join(list(set(x.split(' ')))))
all_lines = ' '.join(list(data_train_sample['text_unique']))
word_count = Counter(all_lines.split(" "))
word_count = sorted(word_count.items(), key=lambda d:int(d[1]), reverse = True)print(word_count[:5])
[('3750', 9890), ('900', 9883), ('648', 9594), ('2465', 8842), ('6122', 8819)]

可以发现’3750’和’900’这两个字符的覆盖率接近99%,所以这很大可能性是标点符号,当然也不排除某些常用的暂停词,比如“是”,“的”等。

句子数目预测

假设字符3750,字符900和字符648是句子的标点符号,那我们可以对句子数目进行统计

python里字符串的split只限单个分隔符对句子进行分隔,而re模块里的可以实现多个分隔符。

import re
data_train_sample['sent_len'] = data_train_sample['text'].apply(lambda x:                                                                         len(re.split('3750|900|648',x)))
data_train_sample['sent_len'] .describe()
sent_len
count 10000.000000
mean 80.465500
std 87.870409
min 1.000000
25% 28.000000
50% 57.000000
75% 102.000000
max 2193.000000

从上表得出这10000个样本文本的句子平均长度为80,最短为1,最长为2193。(前提是以3750,900和648为标点)

类别内字符统计

for i in range(14):data_class = data_train_sample[data_train_sample['label']==i]all_lines = ' '.join(list(data_class['text']))word_count = Counter(all_lines.split(" "))word_count = sorted(word_count.items(), key=lambda d:d[1], reverse = True)print("类别",i,":",word_count[:5])
类别 0 : [('3750', 62357), ('648', 46589), ('900', 28191), ('3370', 25582), ('4464', 15594)]
类别 1 : [('3750', 60881), ('648', 37043), ('3370', 34105), ('900', 27931), ('4464', 26135)]
类别 2 : [('3750', 72344), ('648', 48674), ('900', 30534), ('7399', 17182), ('6122', 16876)]
类别 3 : [('3750', 38544), ('648', 25423), ('900', 14495), ('6122', 9518), ('4939', 8796)]
类别 4 : [('3750', 18241), ('648', 11823), ('900', 9721), ('4411', 5942), ('7399', 4439)]
类别 5 : [('3750', 36044), ('648', 16526), ('900', 15214), ('6122', 8016), ('5598', 6901)]
类别 6 : [('3750', 24660), ('648', 17095), ('900', 11274), ('6248', 9687), ('2555', 9363)]
类别 7 : [('3750', 22275), ('648', 13586), ('900', 9600), ('3370', 8528), ('5296', 7448)]
类别 8 : [('3750', 11716), ('648', 9734), ('900', 4688), ('4939', 3072), ('6122', 2894)]
类别 9 : [('3750', 8187), ('648', 7348), ('900', 3208), ('7328', 2168), ('6122', 2043)]
类别 10 : [('3750', 8171), ('648', 4952), ('3370', 3481), ('900', 3443), ('4464', 2113)]
类别 11 : [('3750', 4263), ('648', 3426), ('900', 1804), ('5560', 1050), ('4939', 1035)]
类别 12 : [('3750', 4334), ('4464', 2787), ('3370', 2641), ('3659', 1907), ('900', 1869)]
类别 13 : [('3750', 967), ('648', 890), ('900', 361), ('4939', 293), ('6122', 277)]

可以看出每个类的出现最多的几个字符都是相似的,所以基本上就是标点或者暂停词了。

结论

通过上述分析我们可以得出以下结论:

  1. 赛题中每个新闻包含的字符个数平均为1000个,还有一些新闻字符较长;
  2. 赛题中新闻类别分布不均匀,科技类新闻样本量接近4w,星座类新闻样本量不到1k;
  3. 赛题总共包括7000-8000个字符;

通过数据分析,我们还可以得出以下结论:

  1. 每个新闻平均字符个数较多,可能需要截断;
  2. 由于类别不均衡,会严重影响模型的精度;
参考文献:
  1. https://ipython.org/ipython-doc/2/api/generated/IPython.core.magics.pylab.html
  相关解决方案