挖掘过程目录:

数据挖掘的流程和方法、技巧总结-赴京书生

具体步骤:

一、探索性数据分析(EDA)

  • 统计基本信息:最大最小值,中位数分位数,均值。使用DataFrame.describle。
  • 单个特征可视化: 对单个特征以及目标特征的各个取值情况做计数,绘制分布图(离散变量:条形图;连续变量:概率分布)。使用DataFrame.count。虽然这部分工作可能对于获取重要信息没有太大帮助,但每次我们发现一个特征的一个有趣的现象时,可以回来查看它的分布情况,并作出解释。另外它有助于我们事先对要探索、逼近的参数有一个基本的了解。
  • 每个特征对于目标变量的影响的可视化:

(1)可以直观地获悉数据特征是否与先验吻合;

(2)对于缺少先验的特征可以知道该变量的重要性,并提供分析解释的切入口(比如某个类别特征在取值某类的时目标都是某某);

(3)举例说明。

(3.1)对于二分类目标变量,我们取定一类为正例,然后以正例比例为考察对象。

(3.1.1)当特征是类别变量或整数变量时,用条形图(均值plot)+上下置信限区域(使用errorbars)可视化该特征各个取值下的正例比例。考察条形图的差异大小(差异很小表示该单特征对于目标的影响很弱,但还需要进一步考察该单特征会不会与其他关联特征组成强特)。

(3.1.2)当特征是连续变量时,则绘制在同一张图里的两个分布,一个表示正例比例,另一个表示负例比例。考察两个分布的重叠区域大小(高度重叠表示该单特征对于目标的影响很弱,但还需要进一步考察该单特征会不会与其他关联特征组成强特)。

(3.2)当目标特征是连续变量时,我们可以对目标设置若干阈值,将其分区间,然后跟上面类似处理,例如三个区间则对每个特征绘制三个分布,或者是(类别个数*3)条直方图。

(3.3)数据有缺失值时,可以把特征的缺失值当做一类,看看是不是目标取某些值时样本经常有缺失值,可以用于判断要不要丢掉这个特征。

  • 多个特征的比较:

进行多个特征之间的相关性分析,可视化相关性矩阵。可以进一步可视化相关系数大的特征对的关系(Pairwise relationship,使用:多类别变量之间:barplot;连续变量之间:scatter plot and linear regression;二类别变量之间:count)。R语言做的一些图(来自kaggle用户:Philipp Spachtholz):

数据挖掘的流程和方法、技巧总结-赴京书生

二、预处理(Preprocessing)

这里介绍的数据预处理部分主要是对异常值和缺失值的处理。使用包含异常值和缺失值数据集的简单策略是丢弃包含异常值和缺失值的整个行和/或列。对于它们的处理方法非常多,下面主要介绍一些比较常用又简单的方法,更多内容可以参考拓展阅读。

1. 异常值(Outliers)

检测、判断方法:

  • 3σ原则和四分位数截断(箱形图法):作用于单个特征。服从正太分布的数据特征,μ±3σ区域应该包含99.7%的数据,所以可以认为这个区间之外的数据为outliers。类似的,四分位数截断是由25%分位数  和75%分位数  定义 它们的差值: ,在区间  外的数据认为是outliers。类似的还有t分布检验法。
  • 基于距离的异常值检测:作用于多维数据。根据某种度量计算样本与样本均值间距离,对距离进行排序,数值过大的当做outliers。
  • 许多作用于单个特征的方法可以拓展到处理多个特征,比如使用多元正太分布(均值向量、协方差矩阵),使用卡方统计量等,可参见拓展阅读。
  • 基于模型算法推断的检测方法,如基于矩阵分解和重构的方法,神经网络自编码器等,这类方法主要是把输入数据转化到另一个空间,或是提取数据特征,然后将这些中间结果映射回原空间,目标是获得和原输入一样的数据。由于正常数据经过两次变换后和原来的区别不大,而异常数据往往无法回到原来的位置,所以可以被检测出来。具体参见拓展阅读。

处理方法:

异常值样本的丢弃与否还是要看情况。如果异常值是一些现实中特殊情况下会出现的数据,在训练模型时如果简单的丢弃,那么我们的数据就成为选择样本,使用模型时(test)是没办法预测那些特殊情况的。针对异常值的检测和处理可以十分复杂,不过一般情况下并且没有特别的要求,直接丢弃异常值是可以接受的。

一些其他的策略,比如(1)异常值替换为认为合理的区间的端点值;(2)连续变量根据分位数或人工限定阈值离散化变为类别变量,消除极端值的影响;(3)使用下面介绍的处理缺失值的方法;等等。(如果你试过这些方法,请告知我它们的效果: D)

第三部分特征工程里也会介绍在数据变换时用于处理异常值的更robust的方法。

2. 缺失值(Missing Value)

sklearn里的大部分算法需要先对缺失值进行处理。除了丢弃含缺失值的数据,一个更好的策略是推算缺失值,即从数据的已知部分推断它们。

缺失值处理:

  • 删除样本:适用于缺失数据的产生是随机的,并且去除缺失值后仍有足够的数据训练模型的情况。
  • 删除变量:如果这个变量的缺失率超过50%,丢掉,除非已经知道它非常重要。
  • 用均值/中位数/众数填补:一般只有在数据波动不是很大,并且该变量对目标变量的影响不大的情况才有很好的效果。
  • 用预测值填补(拓展阅读里有介绍R语言里这部分的工具,python没找到):例如k近邻插补法,具体流程如下:对于每个需要插值的观测,先基于欧氏距离找到k个和它最近的观测。再将这k个近邻的数据利用距离逆加权得到插补值,最后用该值替代缺失值。还有原理类似的回归填补法等。这种处理可能会让属性间的相关性增加,导致线性模型等能力下降。

sklearn的Imputer()支持用均值/中位数/众数的方式填补缺失值,还可以用来处理稀疏矩阵,把0值进行填充替换。sklearn.preprocessing.Imputer - scikit-learn 0.19.1 documentation

此外,lightGBM和XGBoost可以直接处理缺失值(当做数据的一部分进行训练),所以可以不做额外处理。

三、模型(Model)和特征工程(Feature Engineering)

模型和特征工程放在一起介绍,因为特征工程经常是与所使用的模型算法密切相关的。

1. 处理定性特征:

  • 某些定量变量可以转化为定性变量:

比如年龄变量0~80,可以按照一定范围转化为儿童、青少年、中年、老年等的类别变量。

  • 对类别变量进行编码:

(1)标签编码,即一个类别对应一个自然数,编排成0,1,2...;sklearn.preprocessing.LabelEncoder - scikit-learn 0.19.1 documentation

(2)哑变量编码,即一个类别对应一个二值变量,表示是与否,一个有n个类别的原变量编码后成为n个二值变量;sklearn.preprocessing.OneHotEncoder - scikit-learn 0.19.1 documentation

(3)平均数编码,适合用来处理变量的类别很多(n很大)的情况,参考:平均数编码:针对高基数定性特征(类别特征)的数据预处理/特征工程

  • 如果某个类别变量的少部分类别取值占据了该很大比例的样本,甚至是某一类别只出现一次,例如路由器的唯一标识bssid等,可选做丢弃、统计频率构造新特征、上下采样和加权、合并这些高频率且少数目的类别为一个新类别等处理。
  • 类别特征可以分为无序和有序的两种。在做类别特征的相似性度量或者排序时,“序”的特征要有区分。对于有序变量,相似性度量可以使用定量特征的度量方式(比如欧式距离);无序变量则不能,可以用value difference metric。有时候,我们可能要对特征做排序,比如决策树切分数据时,这时必须对类别变量做哑变量编码。

2. 处理定量特征

2.1 无量钢化/中心化和缩放(注意稀疏性和异常离群点):

(1)最小最大缩放,减去最小值后除以最大值和最小值的差,MinMaxScaler可以把数据变化到一个指定的范围(例如(0,1))。sklearn.preprocessing.MinMaxScaler - scikit-learn 0.19.1 documentation

(2)最大绝对值缩放,除以最大绝对值,MaxAbsScaler把每个特征的最大绝对值限制为1,即数据在(-1,1)。这种方式相比(1)不会使得数据发生偏移或中心化,所以不会破坏数据的稀疏性。 sklearn.preprocessing.MaxAbsScaler - scikit-learn 0.19.1 documentation

(1)有明确物理意义的特征,比如经纬度特征,不适合做缩放变化,会破坏物理意义。

(2)如果模型对特征做了一些线性独立性的假设,这时可能做不到独立地中心化和缩放。可以用设置参数whiten=True(拓展阅读里有一篇关于白化的介绍)的PCA变化去消除特征的线性相关性。http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html#sklearn.decomposition.PCA

(3)中心化核矩阵:如果数据是由核函数处理过的,你可能需要用KernelCenterer:sklearn.preprocessing.KernelCenterer - scikit-learn 0.19.1 documentation

(4)More to come...

2.2. 归一化(Normalization)

缩放数据到单位范数,即变换后的单行数据样本的范数为1。文本分类或聚类的常用操作。接受非稀疏的numpy array或者稀疏的scipy sparse sklearn.preprocessing.Normalizer - scikit-learn 0.19.1 documentation

注意归一化和标准化的区别:标准化作用于每个特征列,通过去均值和缩放以方差值的方式将样本的所有特征列转化到同一量纲下;归一化作用于每一数据行,通过缩放以原样本的某个范数使得计算样本间相似度的时候有统一的标准。

2.3. 非线性变化(Non-linear Transform)

3. 构建新特征

3.1. 交叉特征:若干个特征进行组合,创造出有新的物理意义的变量。

  • 定量变量和定性变量的组合。比如对于车辆行驶数据,有时间特征(定性)和车速特征(定量),可以组合出某车辆在工作日/周末/晚上/白天的统计车速作为新特征。使用DataFrame的groupby进行操作:
data['speed_weekend'] = data.groupby('weekend').mean()['speed']
  • 特征的线性组合。比如交易数据,构建今日与昨日收盘价的差值作为新特征。线性组合只用于决策树类模型。
  • 以上两种方式的组合应用。

3.2. 利用经过训练的模型的结果

  • 一种是利用决策树的决策路径信息构建特征。将叶子节点(一个样本对应一片叶子)的Index当做类别变量进行编码,作为新的特征。
  • 一种是将模型的预测概率值(一个样本对应一个概率)放入数据继续训练。

这两种方法我都只听别人说过,不清楚具体效果如何。感觉有过拟合风险。

3.3. 基于实际业务的领域知识等构造特征

结合自身和业务领域知识构建对模型效果有帮助的特征是数据攻城狮最能体现自身价值的任务之一。More to come(maybe not)...

3.4. 其他一些东西

  • 时间特征:年月日时分秒,一年/周里的第几月/天,以此类推。
  • 时间序列:特征的改变量;
  • 手动限制特征的取值范围:pandas dataframe的.clip(low, upper)方法
  • PCA旋转二维特征(例如经纬度)到另一个空间;

(PCA不止可以用来降维,还可以做建模时的客观赋权,构造新特征时的旋转二维数据到另一个空间,甚至做异常数据检测,详情可见我的另一篇文章

  • More to come...

4. 总结模型算法对于特征处理的要求或适用范围

主要是基于决策树的模型和其他模型的差异。

  • 目标函数假定变量服从正太分布的方法,比如RBF核,SVM,L1和L2正则的线性模型等,都需要做标准化处理。
  • 对特征列的单调变化,比如:针对特征列的缩放、偏移变化,非线性变化中的对数变化,三次方变化等,对于决策树类型的算法没有意义。
  • 将连续变量按照其物理意义,设定阈值将其二值化或多值化,对于决策树型的算法的意义也不大。
  • 特征交叉组合中的线性组合只适用于决策树类模型。线性模型,SVM,神经网络等不擅长捕获不同特征之间的线性相关性。
  • More to come...

5. 特征选择和对高维数据的降维

  • Filter more to come...
  • wrapper
  • embedded
  • 实践告诉我们,直接PCA、LDA等进行降维的效果往往并不咋地。

四、模型选择和评价(Model Selection and Evaluation)

  • 按照任务类型来说,对于结果提交型的数据竞赛,一般追求尽可能高的准确率,使用XGBoost,lightGBM,进行模型的Ensemble等。对于写作型的数据竞赛,需要考虑介绍模型时的方便和模型的可解释性,线性的模型是大家的最爱。当然,经常要根据实际情况进行拓展或使用非线性模型。对于实际业务项目,也需要考虑模型训练、测试的开销花费等问题,经常选择简单而且效果不错的模型。
  • 线性模型,SVM,神经网络和决策树类模型。more to come...
  • Cross-Validation,Tuning Parameters,Evaluation Metrics,Validation Curve and Learning Curve。
  • 工程中做ensemble的方法。

拓展阅读:

赞赏

数据挖掘的流程和方法、技巧总结-赴京书生微信赞赏数据挖掘的流程和方法、技巧总结-赴京书生支付宝赞赏