工具:Pandas v1.0.5,Python v3.6
1. 数据读取与输出
import pandas as pd
path_train_data = r'F:\DW_NLP\Competition_Data\train_set.csv'
train_df = pd.read_csv(path_train_data, sep='\t', nrows=100) # pandas读取数据,先只读取前100行
print(train_df.head())
主要用到read_csv(),用法:三个statement,第一个是要读取的文件路径,第二个是分隔符sep,分割每一列,第三个是读取行数nrows,是数值类型。
head(n):查看对象的前n行。如果不给n赋值,只输出5行。
输出结果:
2. 数据分析
包含:句子长度,新闻类别分布,字符分布
通过数据分析找出文本规律,尤其本次文本是按照字符级匿名化处理后的,无法直接使用中文文本处理方法,找出其中的规律更加重要。
目标:新闻文本长度;类别分布;字符分布。
做数据分析,要读取全部数据。可以使用 train_df.shape 查看读取后的数据行列大小。先分析句子长度赛题数据中每行句子的字符以空格分开,直接统计单词个数来计算每个句子长度。
import pandas as pd
path_train_data = r'F:\DW_NLP\Competition_Data\train_set.csv'
train_df = pd.read_csv(path_train_data, sep='\t') # pandas读取数据
# print(train_df.head())
print(train_df.shape) # 读取的数据行列大小
train_df['text_len'] = train_df['text'].apply(lambda x: len(x.split(' ')))
print(train_df['text_len'].describe())
train_df['text']
:根据列名text,并以Series的形式返回列。
split()
: 通过指定分隔符对字符串进行分割,返回列表。
.apply(pd.Series.value_counts)
:对“text”这一列的每行文本进行括号内的函数处理,此处是求 split() 返回的列表的长度,传给 train_df[‘text_len’] 。
关于apply使用的一个例子:
>>>df = pd.DataFrame([[4, 9]] * 3, columns=['A', 'B'])
>>>df
A B
0 4 9
1 4 9
2 4 9
>>>df.apply(np.sqrt)
A B
0 2.0 3.0
1 2.0 3.0
2 2.0 3.0
.describe()
:查看数据值列的统计变量。
统计值变量说明:
count:数量统计,此列共有多少有效值
mean:均值
unique:不同的值有多少个
std:标准差
min:最小值
25%:四分之一分位数
50%:二分之一分位数
75%:四分之三分位数
max:最大值
输出结果:
发现:75%的数据样本长度不超过1200个字符,绘制直方图,看数据分布:
import matplotlib.pyplot as plt
_ = plt.hist(train_df['text_len'], bins=200)
plt.xlabel('Text char count')
plt.title("Histogram of char count")
plt.show()
输出结果:
再分析新闻类别分布。具体统计每类新闻文本的样本个数。
train_df['label'].value_counts().plot(kind='bar')
plt.title('News class count')
plt.xlabel("category")
plt.show()
输出结果:
在数据集中标签的对应的关系如下:{‘科技’: 0, ‘股票’: 1, ‘体育’: 2, ‘娱乐’: 3, ‘时政’: 4, ‘社会’: 5, ‘教育’: 6, ‘财经’: 7, ‘家居’: 8, ‘游戏’: 9, ‘房产’: 10, ‘时尚’: 11, ‘彩票’: 12, ‘星座’: 13}
类别分布情况规律:主要为 科技、股票、体育、娱乐、时政 这5类(0-4),每一类都超过1w个样本,10-13这几类每类不超过5000个样本。
最后进行字符分布统计。统计每个字符出现的次数。将训练集中所有句子进行拼接,然后划分字符,并统计每个字符的个数。
from collections import Counter
import pandas as pd
path_train_data = r'D:\DataWhale\DW_NLP\Competition_Data\train_set.csv'
train_df = pd.read_csv(path_train_data, sep='\t') # pandas读取数据
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) # 按照降序排序,字典起始位就是出现次数最多的字符的出现次数
print(len(word_count))
print(word_count[0])
print(word_count[-1])
' '.join(list(train_df['text']))
:将列表 train_df[‘text’] 中的每个元素用空格连接起来。该列表中每个元素就是每一条样本。
all_lines.split(" ")
:用空格作为分隔符,把 all_lines 按照其中的空格分割成元素(这个元素就是一个个字符),以列表形式返回。
Counter()
:该函数对返回的列表进行每个元素出现次数的统计。以字典的键值对形式存储,其中元素(字符)作为key,其计数作为value。
输出结果:
训练集中共包含6869个不同的字符,编号3750的字符出现7482224次,次数最多,编号3133的字符出现1次,次数最少。
还可以根据字符在每个句子的出现情况,反推出标点符号。下面代码统计了不同字符在句子中出现的次数,其中字符3750,字符900和字符648在20w条样本中的覆盖率接近99%,很有可能是标点符号。
import pandas as pd
path_train_data = r'D:\DataWhale\DW_NLP\Competition_Data\train_set.csv'
train_df = pd.read_csv(path_train_data, sep='\t') # pandas读取数据
train_df['text_unique'] = train_df['text'].apply(lambda x: ' '.join(list(set(x.split(' ')))))
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)
print(word_count[0])
print(word_count[1])
print(word_count[2])
输出结果:
通过上述分析我们可以得出以下结论:
- 题中每个新闻包含的字符个数平均为900多个,还有一些新闻字符较长;
- 题中新闻类别分布不均匀,科技类新闻样本量接近4w,星座类新闻样本量不到1k;
- 赛题总共包括7000左右的字符;
- 每个新闻平均字符个数较多,可能需要截断;
- 由于类别不均衡,会严重影响模型的精度;
3. 作业:
- 假设字符3750,字符900和字符648是句子的标点符号,请分析赛题每篇新闻平均由多少个句子构成?
import re # re用于split同时指定多个分隔符
import pandas as pd
path_train_data = r'D:\DataWhale\DW_NLP\Competition_Data\train_set.csv'
train_df = pd.read_csv(path_train_data, sep='\t') # pandas读取数据
train_df['text_sentence'] = train_df['text'].apply(lambda x: len(re.split('3750|900|648', x))) # 字符与字符之间用“或”隔开,re.split返回的也是列表
print(train_df['text_sentence'].describe())
输出结果:
- 统计每类新闻中出现次数最多的字符。
import pandas as pd
from collections import Counter
path_train_data = r'D:\DataWhale\DW_NLP\Competition_Data\train_set.csv'
train_df = pd.read_csv(path_train_data, sep='\t', nrows=200) # pandas读取数据
vec = {} # 定义字典
for i in range(len(train_df["label"])):
if train_df["label"][i] not in vec:
vec[train_df["label"][i]] = train_df["text"][i]
else:
vec[train_df["label"][i]] = vec[train_df["label"][i]] + ' '
vec[train_df["label"][i]] = vec[train_df["label"][i]] + train_df["text"][i]
for key in vec.keys():
word_count = Counter(vec[key].split(" "))
word_count = sorted(word_count.items(), key=lambda d: (d[1]), reverse=True)
print(key, word_count[0])
先把代码贴在这里,目前还没有运行完,结果之后再放。如果读取全部数据进行统计,代码运行时间过长,先取200行数据进行了输出结果如下:
在进行统计时,没有去掉字符3750,字符900和字符648,输出的结果中每类文本中出现最多的字符基本都是3750。之前认定这三个字符为标点,后面可以去掉这三个字符后,再进行统计,看一下除标点之外的每类文本中出现次数最多的字符,可能更具有特征性。或者,输出时判断word_count的字符是否是这三个字符的其一,是的话判断第二多的字符及次数,类推;不是的话直接输出。