一.文本分类pipeline
文本分类主要是将一个文本归结为特定的某个标签
1.数据预处理:清洗,分词等
你的数据可能比较脏,比如带html标签,不合法的数据,你需要去除
你的文本数据可能需要分词,然后再去掉一些停用词及标点
2.特征构造:词特征+其它特征
一般情况下我们会使用词特征作为文本分类的特征
你还可以增加其它人为定义的特征,比如:文本长度,n-gram特征(将连续的n个词当成一个词特征)等
3.特征选择:卡方,互信息等
用词做特征,不做特征选择,很容易出现上万维,甚至几十万维,这对计算来说可能是个灾难,即使计算资源充足,那也是对资源的浪费,因为真正对分类起作用的词,可能就只是一小部分
经常使用卡方检验,互信息等指标筛选1000-5000维的特征
4.权重计算:TF,TFIDF等
使用了词特征,还有一个重要的点就是如何为每个特征赋值,常见的权重有:TF(词频),TFIDF(词频*倒排文档频率)
至此,我们得到了样本特征矩阵
5.归一化:标准化,归一化等
在实践中,我们往往需要对连续的特征进行标准化和归一化,即让不同特征的取值范围差别不能过大
标准化和归一化可以加快模型训练收敛速度,可能会提高模型精度
对于离散的特征,我们需要使用OneHot进行编码
6.数据集划分:留出法,交叉验证等
我们往往需要使用留出法或者交叉验证法,对数据进行训练集,验证集,测试集的划分
训练集用来训练模型,验证集用来调参,测试集用来评估模型泛化效果
7.训练分类模型:单个,集成
特征矩阵已经就绪,接下来就是要选择一个分类模型,比如:SVM或LR或集成模型RF,然后训练模型
8.模型评估:精度,准确,召回,F1
对于类别分布不怎么均匀的情况,精度并不怎么靠谱,理想的指标是:准确率(准不准),召回率(全不全),F1(两者的折中)
9.参数搜索:网格搜索,随机搜索等
有了指标后,一个分类模型可能有几十个参数,我们该如何选择某个特定的参数组合,使得此时的模型效果最好呢?
可以使用网格搜索,在限定的参数空间内进行调参,也可以使用随机搜索,每个随机选择特定参数组合,然后取n次里面最好的参数组合
10.保存模型:保存模型及参数
选择了最优参数的模型,我们需要将其保存下来,以供后续加载使用
可以用python的pickle库持久化模型对象
11.预测:离线,在线
你可以加载上一步保存的模型,对新的数据进行离线label预测
你还可以将已加载的模型预测功能封装成HTTP服务,提供即时预测功能
二.特征预处理
1.模型的输入
模型需要的输入是样本特征矩阵
对于传统文本分类任务来说,我们经常使用词作为特征,使用频数或者TFIDF作为特征权重
在传统机器学习中,特征的构造极为关键
文本分类中,光有词特征有时候还不够,还可能引入其它特征比如文本长度,文本来源等
2.离散特征onehot编码
定义:主要是采用n位状态寄存器来对n个状态进行编码,每个状态都有它独立的寄存器位,并且在任意时候只有一位有效
onehot编码将一个离散特征编码为n个二进制特征(取值为0或1),n为离散特征的取值个数
意义:将离散特征转换为机器学习易于利用的一种形式
很多机器学习模型假设所有特征的取值是连续的,即它们之间具有可比较的大小关系
离散特征并不具备大小可比的关系
离散特征经过onehot后,被具备了连续特征的可比较关系
3.连续特征的标准化和归一化
即让不同特征的取值范围差别不能过大
为什么需要标准化和归一化?
加快模型训练收敛速度
可能会提高模型精度
归一化
如果不进行归一化,由于不同特征的取值相差较大,会导致目标函数变扁,这样在进行梯度下降求解模型参数时,梯度的方向就会偏离最小值的方向,走很多弯路,即训练时间过长
如果归一化后,目标函数会变圆,训练速度大大加快,少走很多弯路
标准化
通过计算训练集中样本的均值和标准差,对每个特征单独进行中心化和缩放
sklearn标准化有两种实现方式:
①调用sklearn.preprocessiong.scale()函数
②实例化sklearn.preprocessing.StandardScaler()类
最小最大归一化
通过最小最大归一化,我们将特征取值统一到[0,1]
最大绝对值归一化
按其最大绝对值缩放每个特征
对比
相比最大绝对值归一化,最小最大值归一化更常用些
使用归一化来缩放数据,则数据将更集中在均值附近,这是由于归一化的缩放是拍扁统一到区间(仅由极值决定)
标准化的缩放是更加弹性和动态的,因为它保留了样本的特征值分布情况
所以归一化不能很好地处理离群值,而标准化对异常值的鲁棒性强,在许多情况下,标准化优于归一化
4.词袋法和TFIDF
文本数据的词袋法
词袋模型忽略掉文本的语法和语序等要素,将一个文本看作是若干个词汇的集合,文档中每个单词的出现都是独立的
可以使用词频或布尔值来作为权重,显然,使用词频作为权重更为合理
在scikit-learn中,我们使用CountVectorizer将分好词的文本转化为词袋法表示的文档词频矩阵
TFIDF
在实践中,权重矩阵往往是通过tfidf来计算的,它在词频的基础上,还考虑了文档频率,tfidf是一种非常普遍,有效的权重计算方式
TF:展示了文档中每个词出现的频率,频率越高,就越重要
IDF:展示了某个词在所有文档中出现的频率,文档频率越低,即逆文档频率越高,则词越重要
总之,tfidf的意思是说,词的重要性,随着在一个文档中出现的次数增多而变大,随着在所有文档中的出现次数增加而变小
scikit-learn提供了两个获取tfidf的方式:
TfidfVectorizer:直接处理原始文本,获取tfidf
TfidfTransformer:处理词频矩阵,常常接在CountVectorizer后面
三.降维与特征选择
1.为什么要降维与特征选择?
直接使用所有的特征训练模型,会耗费大量的计算资源开销
模型在高维特征下,往往需要更多的训练数据才能训练好,但我们的训练数据有限
基于此,我们需要进行降维,对于机器学习而言,常见的降维方式有两类:
①基于矩阵分解的降维,以PCA,SVD为代表
②基于特征选择的降维,以卡方检验,L1正则化等为代表
2.矩阵分解降维
①线性降维
一般来说,想要实现降维,即将高维空间映射到低维空间,最简单的方法就是对原始高维空间进行线性变换,即乘上一个变换矩阵
对于线性降维来说,最重要的就是变换矩阵的构造,下面所说的主成分分析,奇异值分解都是线性降维的代表
②主成分分析(PCA)
假设让你把二维空间上的一些点,降维投影到一维空间(即某条直线)上,要尽量保留这些点的分布,你会注意什么?肯定是让投影后的点在直线上最大的分开
对于主成分分析来说,实现的方式:最大化投影点的方差
③奇异值分解(SVD)
④对比
在真实的降维场景下,使用PCA或者SVD基本都能满足我们的需求,但这两个方法还是有一些差异的:
在运行PCA时,首先会对数据进行居中处理,这便于后续的计算,但在运行SVD时,并没有对此数据居中处理
由于第一点,导致scikit-learn实现的PCA并不兼容稀疏矩阵,因为对稀疏矩阵居中,可能导致矩阵不再稀疏,而SVD没有这个负担,因此它可以直接处理稀疏矩阵
3.特征选择
①低方差特征过滤
sklearn.feature_selection.VarianceThreshold(threshold=0.0)
②卡方检验和互信息
sklearn.feature_selection.chi2(x,y)
sklearn.feature_selection.SelectKBest(score_func=<function f_classif>,k=10)
sklearn.feature_selection.mutual_info_classif(x,y,discrete_feature='auto',n_neighbors=3,copy=True,random_state=None)
对比
chi2特征选择的速度优于互信息特征选择
从实践的效果来看,几千个特征词时,chi2的效果也是优于互信息的,所以一般情况下我们会优先使用chi2
③L1正则化和基于树的特征选择
前面我们的思路是:先进行特征选择,然后再训练模型,然而有些模型在其训练过程中会自动进行特征选择,比如:L1正则化的模型,基于树的模型等
L1正则化可以做特征选择的主要原因是:它容易获得参数的稀疏解,稀疏解对应的特征可以认为不重要
基于树的模型可以做特征选择的主要原因是:树模型会对每个特征计算基于不纯度的特征重要性
L1正则化
模型的求解即模型参数的求解,参数的求解过程会使用到目标函数,训练时,目标函数定义了模型结果与真实结果的误差
基于树模型的特征选择
树模型会对每个特征计算不纯度,这个不纯度可以用来衡量特征重要性