自然语言处理实践(新闻文本分类)-Task2 数据分析

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()
图2.1 文本长度的分布直方图

可以看到绝大多数的文本长度都是在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()
图3.1 各类别新闻数量统计

可以看出各类别的数据分布是很不平衡的。多的接近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)
图5.1 句子长度分布情况
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

从这个结果中我们可以发现实际上还有好多其他的停用词是我们没有发掘出来的,在进行后续的工作前有必要将它们都找出来并进行适当的处理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值