关于机器学习你应该知道的事

机器学习或者称作数据挖掘(data science&data mining)是计算机科学、统计学和软件工程学的交叉学科,原则上都是通过在大量累积的数据中发现规律并为业务带来经济效益或提供评估依据的过程。实践项目的整个过程中会不断的遇见不同的商业模式、业务类型,并通过结合数学计算机工具来解决实际问题,让整个工作充满了挑战和趣味性。回想起自己第一次接触机器学习的项目,抱着一本Bishop的<Pattern Recognition and Machine Learning>啃了半天,那个时候真是一头雾水。后来经历了第一个kaggle比赛后,逐步的上手了解了整个机器学习的过程,于是想要写一下关于表格类比赛一般应该考虑的主要步骤,以供大家参考指正。

从Kaggle和项目的经验中来看,整个过程最重要的原则是两个点:

  1. 如何定义可验证的评价指标, 形成业务闭环
  2. 确保每一个操作都有信仰,合理且符合逻辑

一般来说整个流程包含以下要素(如下图所示),这些要素每个部分都需要细致的分析和解释,这里仅仅是列出这些步骤, 并介绍相关模块下最常用的一些库。

机器学习主要流程步骤

数据概览

数据概览,一般称之为EDA(Exploration Data Analysis), 主要负责对数据进行清洗以及初步认识数据, 包括有哪些categorical特征,数值类特征的分布如何等等。 一般都是利用Pandas, Numpy, Jupyter notebook 和一些可视化工具(plotly, matplotlib, seaborn)。 其中最常见的是利用Pandas表示数据,在做初步分析的时候建议使用一些简单的系统化工具执行这一步骤(例如pandas_profiling),简单快捷获取到最初步的数据概览情况。

import pandas_profiling
train.profile_report()

交叉验证和目标函数

对数据有了基本的认识后,就需要定义一套评价整体模型的框架,交叉验证(cross validation) 和目标函数需要在这个阶段先确定下来。这两个部分的选择都非常依赖于具体问题,不同的数据不同的业务问题需要采用不同的目标函数和交叉验证方法。参考原则在于不同的CV方式是否能够保证样本同分布,目标函数是否满足研究的问题 (比如如何看待离群点,是否均衡看待偏大或者偏小两种情况)。实操层面通常都是利用sklearn来实现这两部分的功能, 具体可以参见 sklearn.metrics 和 sklearn.model_selection 两个模块查看最常见的相关方法。如果是深度学习模型可以参考相关的pytorch loss等。同时也应该考虑能否做数据增强 (data argumentation),来提高模型的泛化能力。

特征工程

特征工程应该是整个流程中最重要的一个部分,有种说法是数据决定了整个系统精度的上限,而特征工程和模型很大程度上决定了能否达到这个上限, 所以特征工程是决定能否取得一个满意效果的重要因素。Kaggle比赛主要就是考验大家是否对数据敏感,能否找到 magic feature. 一般的操作流程为:

  1. 数据缺失和数据异常修正;
  2. 衍生特征制作方法;
  3. 是否考虑降维和embedding;
  4. 归一化和同分布考虑;

同时在之前确定的目标函数和交叉验证的框架下,评估不同特征和操作的好坏,留下有用的操作和特征的同时丢弃其他的。 该部分具体操作有很多的技巧和经验,也需要很多的想象力,这里我们先罗列一些基本的步骤,之后会有专门的整理博文 详细介绍该部分的具体实现方法和技巧。于此同时,还建议读读该文章了解基本的过程。 (An Introduction to Variable and Feature Selection)

数据缺失与异常处理

原始数据通常都存在数据缺失的情况,不幸的是除lightgbm等少数模型以外, 并不是所有模型都能内部处理缺失数据(例如Logistic Regression), 所以需要对缺失数据进行删除或补全. 数据补全方式有很多种,除了通常均值或者中位数替代外,还有很多fancy的操作方式,具体方法可以参考 fancy impute 。 与此同时,也需要剔除特征中的一些outlier数值,这些数值通常会降低模型的判断精度, 例如对于出现次数非常少的特征可以用统一的编码(i.e. -999)进行处理。

值得注意的是,在利用lightgbm模型处理NaN值时,在每个树节点上它都会分裂, 将非NaN值和NaN值分别分在两个子树上。 这种处理方法可能会过度重视了NaN值样本, 如果简单的把NaN值改为一个样本中没出现过的数值,那么模型不会特别对待这类样本。 通常需要测试上述两种方法,看哪一种处理方式能够获得更好的CV score。

衍生特征制作方法

特征制作通常有两种方式,第一种是将训练集和测试集concat到一起,然后统一操作。例如在做Label Encoding的时候就必须如此统一操作。

df = pd.concat(train, test, axis=0)
# DO FEATURE ENGINEERING HERE
train = df[:len(train)]
test = df[len(train):]

第二种方式则更加通用, 可分别对训练集和测试集做特征:

df = train
# DO FEATURE ENGINEERING HERE
df = test
# DO FEATURE ENGINEERING HERE

具体在制作特征时应考虑以下角度进行分析:

  1. 在纸上列出所有的特征, 考虑不同特征的组合和衍生;
  2. 区分数值类特征和类别特征,分别进行特征制作;
特征分裂和组合

有些类别类特征包含了多个维度的信息,有可能分开考虑会提供更加丰富的信息, 例如地址 A区B街道 可以尝试拆分为 A区 和 B街道 两个特征。 相反的有些特征如果组合起来(interaction) 和target的相关性更高,所以都应该考虑和尝试。

数值类特征

数值类特征是最常见的特征类型,通常对于数值类特征考虑以下几个问题:

  1. 数值大小重要么? 是不是只需要考虑正负就可以,或者只需要在非常稀疏的尺度上考虑数值即可
  2. 数值尺度是什么样的?最大值和最小值之间是不是差了很多个数量级
  3. 数值特征的分布如何?该数据反映了出现不同数值的概率

数值特征也可以考虑相互组合形成新的特征,也可以考虑通过数学变换改变数据的分布状态等等。

类别类特征

类别类特征由于通常都是由字符串表示,所以需要将该类特征转换为数值从而交给模型进行处理, 这一过程一般称为encoding。类别类特征编码的方式也存在很多很多种, 通常来讲没有某一种编码方式一定优于其他的编码方式,所以选择编码方式这一过程就需要一定的经验和分析。 具体来讲类别类特征又可以细化为一下几种类型:

  1. binary features (类型只有0和1两种结果)
  2. nominal features (有限类型,各类型间没有大小关系,例如省份等)
  3. ordinal features (有序类别,各个类型间有大小关系,例如衣服尺码)
  4. cyclical features (周期类别,特征有周期性,例如月份,星期等)

针对 ordinal feature 通常采用 ordinal encoder而针对cyclical features 可以采用 sine encoder. 对于nominal features 编码方式有很多种,具体可以参考 package category_encoders. DataFrame 中的类别类特征通常用 object 作为数据类型, 可以考虑转换为 category 数据类型从而加速计算过程。

特征降维

在特征制作过程中,很可能特征维度非常巨大,例如如果采用One Hot encoding编码的类别类特征就可能带来维度灾难。 所以可以考虑在最大可能保留信息的前提下,利用降维方法来减少特征空间的维度, 常用的降维方法有 Principle Component Analysis (PCA)Singularity Value Decomposition(SVD) 和 manifold learning 等,也可以在一开始就考虑用embedding的方式来处理。

特征归一化(Feature Scaling or Normalization)和同分布测试

很多模型在应用之前都需要对特征进行归一化,归一化的方式也有很多种(max-min scaling, variance scaling), 归一化的目的在于,很多特征的维度差别很大,比如说预测房屋价格,房间的个数一般都小于10,但是房间的面积都在一百左右,这样的尺度不同的特征很容易让模型关注在大数值的特征上,显然是不合理的。但是针对树模型 (CART, GBDT, Random Forest 等) 时,一般可以不考虑特征归一化, 因为会在同一个类别内寻找分裂点,除非某类特征的尺度会随时间发生变化。

同分布测试在Kaggle比赛上比较重要,基本思想是 如何样本标签在训练集和测试集上是同分布的, 那么能够反应样本的好特征在两个数据集中也应该是同分布的 。 具体用途又可以分为两类: 第一假设某些特征是具备真实意义的’好特征’,然后是看Private Dataset和Training set 的数据标签是不是同分布的。 这里一般称作 Adversarial Validation , 就是对两个数据集分别打两类标签,然后做一个分类模型,如果这些特征能够很好的区分Training set和Private Set, 说明样本分布不均衡,反之也是测试特征好坏的一种手段。 第二种是在做出特征之后观察所做的特征在 Training Set和Test Set上是否分布均衡,以此来衡量特征的好坏,可考虑采用 Kolmogorov–Smirnov 测试方法。

特征筛选

在制作了一大堆特征之后,通常需要进行特征筛选来剔除不好的特征从而提高模型的预测精度和效率。 特征筛选通常有三大类方法:

  1. filter
  2. wrapper
  3. embedded method

第一种filter方法是不借助任何机器学习模型的,比如利用pearson相关系数来去除高度相关的特征; 第二种wrapper方法是利用机器学习方法来挑选特征又可以分为三个小类(1)Forward(2)Backward(3) Recursive Feature Elimination(RFE). Forward和Backward是指分别通过不断加入和减去特征来看模型的表现能力; RFE的复杂度最高,是不断的尝试不同的特征组合来获得最好的模型效果. Forward和Backward比较一般Forward的效果好一点; 第三种就是embedded方法,这个方法是在模型的过程中就做了的,比如用lasso的方法, 里面用了一范数正则化,会把不重要的特征稀疏化。相关的参考库有:

模型构建

模型构建在机器学习中是一个核心问题,其中包含如何选择合适的模型以及如何对模型进行调优。这里面的方法和技巧需要不断地实践锻炼,这里仅仅列出相关的一些模型和工具作为整理。

模型

超参调优

因为特别容易造成过拟合,所以超参一般不会随时调整,通常在开始搭好baseline的时候调整一下最后在模型部署前的时候再调整一次。

模型融合

打比赛的时候会经常考虑到利用模型融合来提升最后的效果,基本上是一个稳定的上分技巧,屡试不爽。俗话说得好,三个臭皮匠顶一个诸葛亮。通常分为:

  1. bagging (多seed)
  2. multi folds
  3. blending
  4. stacking(模型的结果上面套用模型)
  5. restacking (高阶模型不止用结果也用原始特征或者低阶结果)

StackNet(https://github.com/kaz-Anova/StackNet),便是其中专门用来做融合的框架。值得注意的是,如果不同模型的相关性大于0.99,那么一般融合效果会比较差。具体的介绍可以参考该文章, 介绍的非常详细(https://mlwave.com/kaggle-ensembling-guide/)

后处理

后处理也很重要,包含clip,round等基本的操作外, 一般会考虑如何校正预测集和训练集预测目标的分布情况。 除此之外还会检查:

  • 有没有EDA中发现的规律
  • outlier的处理. (Binary model 或者多个目标的不同 模型 做校正)

以上便是整个机器学习的整体流程以及内部需要关注的一些要点和相关的框架,这些内容还有很多的不足需要补充和更新,但是由于篇幅限制先简单的介绍一下整理流程,后续会根据相关需要再出详细的流程介绍。

发表评论

您的电子邮箱地址不会被公开。