Datawhale零基础入门NLP-Task01-day2

本文主要资源引用:https://tianchi.aliyun.com/notebook-ai/detail?spm=5176.12586969.1002.9.6406111aIKCSLV&postId=118253

本章主要内容为数据读取和数据分析,具体使用Pandas库完成数据读取操作,并对赛题数据进行分析构成。
分别读取训练集与测试集:

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
    需要读取的行数(从文件头开始算起)。有时候文件过大,可以只读前多少行做测试,节省时间。

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

数据读取与数据分析

赛题数据虽然是文本数据,每个新闻是不定长的,但任然使用csv格式进行存储。因此可以直接用Pandas完成数据读取的操作。
十分钟快速入门 Pandas

一. 数据读取

赛题数据虽然是文本数据,每个新闻是不定长的,但任然使用csv格式进行存储。因此可以直接用Pandas完成数据读取的操作。

import pandas as pd 
train_df = pd.read_csv('../data/train_set.csv', sep='\t', nrows=100)

这里的read_csv由三部分构成:

  • 读取的文件路径,这里需要根据改成你本地的路径,可以使用相对路径或绝对路径;

  • 分隔符sep,为每列分割的字符,设置为\t即可,两列之间的竖线(分隔符)

  • 读取行数nrows,为此次读取文件的函数,是数值类型(由于数据集比较大,建议先设置为100)可以不设置(, nrows=100),即读取全部;

train_df.head()
labeltext
022967 6758 339 2021 1854 3731 4109 3792 4149 15…
1114464 486 6352 5619 2465 4802 1452 3137 5778 54…
237346 4068 5074 3747 5681 6093 1777 2226 7354 6…
327159 948 4866 2109 5520 2490 211 3956 5520 549…
433646 3055 3055 2490 4659 6065 3370 5814 2465 5…

上图是读取好的数据,是表格的形式。第一列为新闻的类别,第二列为新闻的字符。

二. 数据分析

在读取完成数据集后,我们还可以对数据集进行数据分析的操作。虽然对于非结构数据并不需要做很多的数据分析,但通过数据分析还是可以找出一些规律的。

此步骤我们读取了所有的训练集数据,在此我们通过数据分析希望得出以下结论:

  • 赛题数据中,新闻文本的长度是多少?
  • 赛题数据的类别分布是怎么样的,哪些类别比较多?
  • 赛题数据中,字符分布是怎么样的?

1. 句子长度分析

在赛题数据中每行句子的字符使用空格进行隔开,所以可以直接统计单词的个数来得到每个句子的长度。统计并如下:


train_df['text_len'] = train_df['text'].apply(lambda x: len(x.split(' ')))
#.apply 遍历,应用到每一行 all sentens
#lambda [arg1 [,arg2,.....argn]]:expression
print(train_df['text_len'].describe())

Populating the interactive namespace from numpy and matplotlib

count     100.000000   #100篇 text count  100

mean      872.320000  #mean 平均长

std       923.138191   #标准差std       923

min        64.000000

25%       359.500000

50%       598.000000

75%      1058.000000

max      7125.000000

Name: text_len, dtype: float64

对新闻句子的统计可以得出,本次赛题给定的文本比较长,每个句子平均由907个字符构成,最短的句子长度为2,最长的句子长度为57921。

PS:检测类型,基本信息


type(train_df) #pandas.core.frame.DataFrame  能用 info();describe()
type(train_df['text']) #pandas.core.series.Series ;describe()

train_df.columns #列名
train_df['text'].columns #不能跑,因为格式
train_df.info() # 显示数据类型 pandas.core.frame.DataFrame
<class 'pandas.core.frame.DataFrame'>  类型
RangeIndex: 100 entries, 0 to 99。 100篇
Data columns (total 3 columns):
label       100 non-null int64  100 篇没缺失
text        100 non-null object
text_len    100 non-null int64
dtypes: int64(2), object(1)
memory usage: 2.5+ KB

下图将句子长度绘制了直方图,可见大部分句子的长度都几种在2000以内。

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

import numpy
import matplotlib
from matplotlib import pylab, mlab, pyplot
np = numpy
plt = pyplot

from IPython.display import display
from IPython.core.pylabtools import figsize, getfigs

from pylab import *
from numpy import *
# https://ipython.org/ipython-doc/2/api/generated/IPython.core.magics.pylab.html
#%pylab inline 在vscode里,加上#%%,其实就是 jupyter 模式
%pylab inline

_ = plt.hist(train_df['text_len'], bins=200)
#hist 直方图
#bins: 像素大小
plt.xlabel('Text char count')
plt.title("Histogram of char count")
Text(0.5, 1.0, 'Histogram of char count')

在这里插入图片描述

2. 新闻类别分布

接下来可以对数据集的类别进行分布统计,具体统计每类新闻的样本个数。

train_df['label'].value_counts().plot(kind='bar')
# 获取第一列。统计每个类别数量。绘图
plt.title('News class count')
plt.xlabel("category")
#不均匀会导致,-> 预测极端,不准确
Text(0.5, 0, 'category')

在这里插入图片描述

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

PS 方法2

pands的每一列领出来,是 series

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

#进阶版,比matplot。散点图
#与原图的区别
class_count = pd.DataFrame(data_train['label'].value_counts()).reset_index()
#sns seaborn  https://blog.csdn.net/ice_martin/article/details/61617053
sns.barplot(x='index',y = 'label',data = class_count)

plt.title('News class count')
plt.ylabel("count")
plt.xlabel("category")

从统计结果可以看出,赛题的数据集类别分布存在较为不均匀的情况。在训练集中科技类新闻最多,其次是股票类新闻,最少的新闻是星座新闻。

3. 字符分布统计

接下来可以统计每个字符出现的次数,首先可以将训练集中所有的句子进行拼接进而划分为字符,并统计每个字符的个数。

从统计结果中可以看出,在训练集中总共包括6869个字,其中编号3750的字出现的次数最多,编号3133的字出现的次数最少。

from collections import Counter
#由于数据集过大,这里可以做了一下采样 
#data_train_sample = data_train.sample(n=10000,random_state=405633) #作用10000,随机种子

#首先可以将训练集中所有的句子进行拼接进而划分为字符
all_lines = ' '.join(list(train_df['text']))
#' '.join 连接两个字符
#list 转换类型,类似 int()
word_count = Counter(all_lines.split(" "))
word_count = sorted(word_count.items(), key=lambda d:d[1], reverse = True)

'''
iterable -- 可迭代对象。 
cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
'''

print(len(word_count)) #100篇 文章所有不重复的字符

print(word_count[0])  # 从第一开始

print(word_count[-1])# index  屁股后头开始数第一个 最小值
2405  #100篇 文章所有不重复的字符

('3750', 3702)

('5034', 1)

PS:

a = word_count.items() #
for x in a:
    
    #print(type(x)) 输出元祖
  #  print(x)
  #  print(x[1]) 输出 词频

这里还可以根据字在每个句子的出现情况,反推出标点符号。下面代码统计了不同字符在句子中出现的次数,其中字符3750,字符900和字符648在20w新闻的覆盖率接近99%,很有可能是标点符号。

from collections import Counter
train_df['text_unique'] = train_df['text'].apply(lambda x: ' '.join(list(set(x.split(' ')))))
#集合里面的元素不能重复,类似于列表。文章·每行·所有单词连接起来
all_lines = ' '.join(list(train_df['text_unique']))
#所有行单词串联,100字符串->1str
word_count = Counter(all_lines.split(" "))
#每个单词出现的次数
word_count = sorted(word_count.items(), key=lambda d:int(d[1]), reverse = True)
#d[1]=第二例,词频
print(word_count[0])

print(word_count[1])

print(word_count[2])
('900', 99) #99 是数

('3750', 99)

('648', 96)

任务

  1. 假设字符3750,字符900和字符648是句子的标点符号,请分析赛题每篇新闻平均由多少个句子构成?
  2. 统计每类新闻中出现次数最多的字符

解答:假设字符3750,字符900和字符648是句子的标点符号,但分隔每个句子都是通过句号,所以我们得先找出句号。一般而言,句号出现在句子末尾,那么每个文本的最后一个字符就应该是句号。我们可以检测一下:

data_train_sample['last_word'] = data_train_sample['text'].apply(lambda x: x.split(' ')[-1])
# 取每个句子【text】的 。,sers.apply
data_train_sample['last_word'].value_counts()
#4172(10000)
900     4172
2662    2023
885      741
1635     370
2465     350
        ... 
3944       1
7042       1
4744       1
2484       1
4180       1

可以看到在文本最后一个字符里,“900”出现次数最多,占接近一半。所以这里假设“900”为句号。

data_train_sample['sent_len'] = data_train_sample['text'].apply(lambda x:                                                 len(x.split('900'))) #用句号去分离每片文章,得出每片文章的句数


sent_len
count10000.000000
mean17.253200
std19.339811
min1.000000
25%7.000000
50%12.000000
75%22.000000
max670.000000

从上表得出这10000个样本文本的句子平均长度为17,最短为1,最长为670。

如果要这三个标点都能作为分隔符的话,python里字符串的split只限单个分隔符对句子进行分隔,而re模块里的可以实现多个分隔符。

import re #模块reluation 
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
count10000.000000
mean80.465500
std87.870409
min1.000000
25%28.000000
50%57.000000
75%102.000000
max2193.000000

类别内字符统计

# pandas 基础 https://blog.csdn.net/zhangchuang601/article/details/79583551
# pandas 选取特定的行;列

for i in range(14): #jupyter 
  
    data_class = data_train_sample[data_train_sample['label']==i] #datafram,为0 的所有文章
    all_lines = ' '.join(list(data_class['text'])) #同一个类的新闻,用空隔连接起来
    word_count = Counter(all_lines.split(" ")) #counter 
    word_count = sorted(word_count.items(), key=lambda d:d[1], reverse = True)
    print("类别",i,":",word_count[:5])
    #pandas.groupby() 对数据进行聚合

同理可以使用pandas.groupby()
pandas.groupby()

数据分析的结论

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

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

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

  1. 每个新闻平均字符个数较多,可能需要截断;
  2. 由于类别不均衡,会严重影响模型的精度;
类别 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)]

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

本章小结

本章对赛题数据进行读取,并新闻句子长度、类别和字符进行了可视化分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值