Task2主要内容为数据的读取与分析。
数据读取
赛题数据虽然是文本数据,每个新闻是不定长的,但任然使用csv格式进行存储。因此可以直接用Pandas
完成数据读取的操作。
train_df = pd.read_csv('input/train_set.csv', sep='\t', nrows=100)
sep表示该文本数据是由\t隔断,nrows表示读取前100行,这俩参数之前是没有用过的。
我们调用head函数来看一下数据的构成,很简单,第一列是分类的target,第二列为新闻的字符。
下面的内容摘自同小队的队长,详见https://zhuanlan.zhihu.com/p/162749684
内存不足怎么办?
如果内存不足,没法一次性读取20万条数据怎么办?
可以使用
chunksize
参数,这时候返回的是可迭代的对象TextFileReader
,而不是DataFrame
,可以通过迭代TextFileReader
来获取长度为chunksize
的小块DataFrame
:train_tfr = pd.read_csv('data/train_set.csv', sep='\t', chunksize=20000) for chunk in train_tfr: do_sometime(chunk) # 这里的chunk是DataFrame,和下面的操作一样,不过需要额外变量以整合所有分块的统计数据
上面是分块读取的,下面介绍的是另一种方法:
iterator
参数。这个参数的好处是,如果你只想看看数据,比如前10行,就可以通过这样的方法来查看。同时分批取数据也更加灵活,比如说,我第一次想取100条数据,第二次想取50条。每一次取数据的索引号是接着上一次的索引号的。train_tfr = pd.read_csv('data/train_set.csv', sep='\t', iterator=True) train_tfr.get_chunk(5)
数据分析
之前的经历里接触的数据分析都是结构化的数据,如何对非结构化的数据进行分析呢?在本题目中,我们主要关注以下几个方面:
- 赛题数据中,新闻文本的长度是多少?
- 赛题数据的类别分布是怎么样的,哪些类别比较多?
- 赛题数据中,字符分布是怎么样的?
想dataframe中加入一列text_len,表示新闻字符串的长度
train_df['text_len'] = train_df['text'].apply(lambda x: len(x.split(' ')))
对该列调用describe()方法,查看其统计信息:
Populating the interactive namespace from numpy and matplotlib
count 200000.000000
mean 907.207110
std 996.029036
min 2.000000
25% 374.000000
50% 676.000000
75% 1131.000000
max 57921.000000
Name: text_len, dtype: float64
仅从统计信息来看,中位数为676,平均数为907,不算很长,但是也不短(考虑BERT的max_len为512),因此后续我们会考虑对文本进行处理,例如截取、清洗。
接下来来看标签的分布。
train_df['label'].value_counts().plot(kind='bar')
plt.title('News class count')
plt.xlabel("category")
从可视化的结果来看,存在一定的分布不均匀情况,这会对模型有一定的影响。
接下来我们来分析字符相关的信息。
因为training data经过了匿名化的处理,因此我们无法用stop word list来处理,这里我们可以分两个方向考虑:
- 在所有新闻中大量出现的,可能是一些没意义的词;
- 在大部分句子中都出现的,可能是标点符号,可以删掉。
# Issue 1
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)
# Issue 2
# Remove duplicate for each news text.
train_df['text_unique'] = train_df['text']\
.apply(lambda x: ' '.join(list(set(x.split(' ')))))
# Concatenate all together.
all_lines = ' '.join(list(train_df['text_unique']))
word_count = Counter(all_lines.split(" "))
word_count = sorted(word_count.items(), key=lambda d:int(d[1]), reverse = True)
作业
仅记录下思路。
作业1:假设字符3750,字符900和字符648是句子的标点符号,请分析赛题每篇新闻平均由多少个句子构成?
- 三者为标点符号,要算每篇新闻由多少句子组成。根据常识,我们知道一篇文章中逗号最多,句号总会出现在文章的最后,此处有三个标点符号,我们可以分别假设最后一个符号是句末标点,或者为句中标点;
- 具体实现上,我们可以:
- 统计三者出现的频次,最高的为逗号;
- 统计每一篇文章的最后一个符号的value count,最多的胃句号。此处若与上一步的结果一致,则上一步,逗号应为出现次数次高的那个token;
- 假设最后一个token是句中标点,则仅需对每条新闻用句号做分割,计算句子数量即可。假设是句末标点,则同时用两种token做分割即可。
作业2:统计每类新闻中出现次数对多的字符
简单的groupby后加和,或者按列值加和,即可。