一、NLP 赛题理解
1.1 题目
赛题介绍:https://tianchi.aliyun.com/competition/entrance/531810/introduction
赛题以匿名处理后的新闻数据为赛题数据,数据集报名后可见并可下载。赛题数据为新闻文本,并按照字符级别进行匿名处理。整合划分出 14 个候选分类类别:财经、彩票、房产、股票、家居、教育、科技、社会、时尚、时政、体育、星座、游戏、娱乐的文本数据。
赛题数据由以下几个部分构成:
训练集 20w 条样本,测试集 A 包括 5w 条样本,测试集 B 包括 5w 条样本。
为了预防选手人工标注测试集的情况,将比赛数据的文本按照字符级别进行了匿名处理。评价标准为类别 f1_score 的均值,选手提交结果与实际测试集的类别进行对比,结果越大越好。
处理后的赛题训练数据如下:
在数据集中标签的对应的关系如下:{‘科技’: 0, ‘股票’: 1, ‘体育’: 2, ‘娱乐’: 3, ‘时政’: 4, ‘社会’: 5, ‘教育’: 6, ‘财经’: 7, ‘家居’: 8, ‘游戏’: 9, ‘房产’: 10, ‘时尚’: 11, ‘彩票’: 12, ‘星座’: 13}
1.2 评测指标
评价标准为类别f1_score的均值,选手提交结果与实际测试集的类别进行对比,结果越大越好。
1.3 大体思路
文本分类问题,需要根据每句的字符进行分类。难点是需要对匿名字符进行建模(不能直接使用中文分词等操作),进而完成文本分类的过程。由于文本数据是一种典型的非结构化数据,因此可能涉及到特征提取和分类模型两个部分。
思路1:TF-IDF + 机器学习分类器
直接使用TF-IDF对文本提取特征,并使用分类器进行分类。在分类器的选择上,可以使用SVM、LR、或者XGBoost。
思路2:FastText
FastText是入门款的词向量,利用Facebook提供的FastText工具,可以快速构建出分类器。
思路3:Word2Vec + 深度学习分类器
WordVec是进阶款的词向量,并通过构建深度学习分类完成分类。深度学习分类的网络结构可以选择TextCNN、TextRNN或者BiLSTM。
思路4:Bert词向量
Bert是高配款的词向量,具有强大的建模学习能力。
二、读取比赛数据
天池:https://account.aliyun.com/login/login.htm
下载比赛数据集,https://tianchi.aliyun.com/competition/entrance/531810/introduction
读取比赛数据集,读取代码:
import pandas as pd # nrows为读取的行数 train_df = pd.read_csv('train_set.csv', sep='\t', nrows=100) train_df['word'] = train_df['text'].apply(lambda x: len(x.split(' ')))
读取数据集的前几行,第一列(label
列)为新闻的类别,第二列(text
列)为新闻的字符:
label text word 0 2 2967 6758 339 2021 1854 3731 4109 3792 4149 15... 1057 1 11 4464 486 6352 5619 2465 4802 1452 3137 5778 54... 486 2 3 7346 4068 5074 3747 5681 6093 1777 2226 7354 6... 764 3 2 7159 948 4866 2109 5520 2490 211 3956 5520 549... 1570 4 3 3646 3055 3055 2490 4659 6065 3370 5814 2465 5... 307
三、对数据集字符进行可视化,统计标签和字符分布
统计数据集中所有句子所包含字符的平均个数
统计数据集中不同类别下句子平均字符的个数
统计数据集中类别分布的规律
统计数据集中不同类别下句子中最常见的5个字符
3.1 句子长度分析
# 句子长度分析 train_df['text_len'] = train_df['text'].apply(lambda x: len(x.split(' '))) print(train_df['text_len'].describe())
apply是作用于每行中,lambda是匿名函数得到每坨东西的单词长度x。
# 绘制单词数直方图,bins指定区间长度 _ = plt.hist(train_df['text_len'], bins = 200) plt.xlabel('Text char count') plt.title("Histogram of char count")
绘制每个单词数对应的数量,bins
指定每个柱子的区间长度。
3.2 新闻类别分布
train_df['label'].value_counts().plot(kind = 'bar') plt.title('News class count') plt.xlabel("category") hist2 = plt.hist(train_df['label']) plt.xlabel('category') plt.title("News class count")
在训练集中科技类新闻最多,其次是股票类新闻,最少的新闻是星座新闻。
如果用上面hist2
的方法也能画:
3.3 字符分布统计
首先可以学习一个字典排序栗子(用到lambda
表达式):
# 字典排序栗子 dict1 = {'a': 1, 'b': 4, 'c': 0} # 以列表形式输出字典dict1的key # dict1.items()为字典的键值对 lst1 = [key for key, value in dict1.items()] print(lst1) # ['a', 'b', 'c'] # 颠倒字典的key:value值 dict2 = {value: key for key, value in dict1.items()} print(dict2) # {1: 'a', 4: 'b', 0: 'c'} # 将字典dict1按照value值进行排序,得到列表形式 lst2 = sorted(dict1.items(), key = lambda x: x[1]) print(lst2) # [('c', 0), ('a', 1), ('b', 4)] """ 这里的items()是字典的键值对,即待排序的对象; key = lambda x: x[1]为前面对象的第二位数据的值(即value)进行排序 key = lambda 变量:变量[维数] """
有了上面基础后,我们现在要统计不同单词的出现次数(并进行排序):
# 字符分布统计 from collections import Counter # 把所有text的元素拼接成一个大字符串 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])
不同的单词的个数: 2405 出现最多的单词: ('3750', 3702) 出现最少的单词: ('5034', 1)
现在要统计不同字符在所有句子中的出现比率,和上面一样也是先拼接成一个包含所有字符的string字符串,为了统计出现的每个单词的出现个数,先去重:' '.join(list(set(x.split(' '))))以空格为分割找到每个单词,然后把这些单词用set去重后再转为list。
后面通过Counter得到得到一个字典列表word_count({'3750': 99, '900': 99}),value即对应单词key的个数。
(下面第一行代码不要被劝退到,看lambda里面的东西,参考上面我的解释~)
# 统计不同字符在所有句子中的出现比率 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({'3750': 99, '900': 99}) word_count = Counter(all_lines.split(" ")) # print("===验证一波===", word_count) 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]) # ('648', 96)表示648字符在20w新闻的出现比率为96%
附:打卡清单
具体打卡要求
需要使用Python环境下Notebook完成任务
需要完成所有的任务细节才算完成一个任务
所有的任务可以写在一个Notebook内