1. 准备工作
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from collections import Counter
df = pd.read_csv(r'./data/train_set.csv', sep = '\t')
print(df.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...
可以看出原数据的结构十分简单,只有标签和文本。其中文本中的每一个字符都用数字进行了替换(匿名化处理),而标签也是用数字来指代的类别。标签的对应的关系如下:{'科技': 0, '股票': 1, '体育': 2, '娱乐': 3, '时政': 4, '社会': 5, '教育': 6, '财经': 7, '家居': 8, '游戏': 9, '房产': 10, '时尚': 11, '彩票': 12, '星座': 13}。这个信息是官网提供的。
另外,由于原始数据的量级较大,如果内存不支持一次读入的话可以在读取时传入nrows参数来决定读取前多少条数据。
2. 统计新闻文本的长度
df['text_len'] = df['text'].apply(lambda x: len(x.split(' ')))
df['text_len'].describe()
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
以上是文本长度的统计结果。可以发现最短的只用2个字符,而最长的可以有57921个字符。
plt.hist(df['text_len'], bins = 200)
plt.show()

可以看到绝大多数的文本长度都是在1000字符以下的。
3. 统计新闻类别的分布
df['label'].value_counts()
0 38918
1 36945
2 31425
3 22133
4 15016
5 12232
6 9985
7 8841
8 7847
9 5878
10 4920
11 3131
12 1821
13 908
Name: label, dtype: int64
df['label'].value_counts().plot.bar()

可以看出各类别的数据分布是很不平衡的。多的接近40000,少的1000都没有,因此后续需要做一些处理来处理不平衡带来的影响。
4. 字符分布统计
4.1 高频字符和低频字符
all_lines = ' '.join(list(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))
print(word_count[0])
print(word_count[-1])
6869
('3750', 7482224)
('3133', 1)
可以看出全体文本一共有6869个不同的字符,其中出现次数最多的是3750,最少的是3133。实际上高频词和低频词远不止这两个。
4.2 高覆盖率的字符
df['text_unique'] = df['text'].apply(lambda x: ' '.join(list(set(x.split(' ')))))
all_lines = ' '.join(list(df['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[0])
print(word_count[1])
print(word_count[2])
('3750', 197997)
('900', 197653)
('648', 191975)
找到前三个覆盖全文本次数最多的字符,当然还有很多其他高覆盖次数的字符。这些字符很有可能是标点符号或者常用但是无实义的词汇。这些词汇最后都应该收录到停用词表中。不过,除了当作停用词,我们还可以用它们来挖掘一些其他的信息。
4.3 尾字符
说到标点符号,对于我们的数据而言,最容易被识别为标点符号的应该就是每条尾部的字符。因此我们有必要再看看尾字符的分布情况。
df['tail_char'] = df['text'].apply(lambda x: x.split(' ')[-1])
df['tail_char'].value_counts().sort_values(ascending = False)
900 85040
2662 39273
885 14473
1635 7379
2465 7076
...
2722 1
5813 1
5374 1
1122 1
4567 1
Name: tail_char, Length: 1897, dtype: int64
可以发现,有一些字符出现在大多数文本的尾部。因此它们很有可能是跟句号功能类似的标点符号。而考虑到前面3750出现的次数非常的高,我们有理由认为3750应该是作用类似于逗号用于句子中间的符号。
df['tail_char_percent'] = df['text'].apply(lambda x: x.split().count(x.split()[-1]) \
/ len(x.split()))
df['tail_char_percent']
0 0.012299
1 0.028807
2 0.001309
3 0.007006
4 0.006515
...
199995 0.001152
199996 0.000876
199997 0.018644
199998 0.005587
199999 0.021926
Name: tail_char_percent, Length: 200000, dtype: float64
横向地看尾字符在同一个文本中出现的频率也可以说明一些问题。
5. 作业
【1】假设字符3750,字符900和字符648是句子的标点符号,请分析赛题每篇新闻平均由多少个句子构成?
def count_sentences(x):
word_list = x.split(' ')
sentences = 0
sentences = x.count('3750') + x.count('900') + x.count('648')
if x[-1] in ['3750', '900', '648']:
return sentences
else:
return sentences + 1
df['sentences'] = df['text'].apply(count_sentences)
df['sentences'].hist(bins = 20)

df['sentences'].mean()
80.80237
这里使用了很粗略的做法,就是把发现出现频次最高的3个字符作为句子的分隔符。实际上根据上面的分析3750是不应该包含在内的。
【2】统计每类新闻中出现次数最多的字符。
grouped = df.groupby('label')
def statistics_top_char(x):
all_lines = ' '.join(list(x))
word_count = Counter(all_lines.split(" "))
word_count = sorted(word_count.items(), key = lambda d: int(d[1]), reverse = True)
for i in word_count:
if i[0] not in ['3750', '900', '648']:
return i
top_char = grouped['text'].apply(statistics_top_char)
top_char
label
0 (3370, 503768)
1 (3370, 626708)
2 (7399, 351894)
3 (6122, 187933)
4 (4411, 120442)
5 (6122, 159125)
6 (6248, 193757)
7 (3370, 159156)
8 (6122, 57345)
9 (7328, 46477)
10 (3370, 67780)
11 (4939, 18591)
12 (4464, 51426)
13 (4939, 9651)
Name: text, dtype: object
从这个结果中我们可以发现实际上还有好多其他的停用词是我们没有发掘出来的,在进行后续的工作前有必要将它们都找出来并进行适当的处理。