此部分的内容应该是整个比赛当中最重要的部分:特征工程
好特征即使使用一般的模型,也能得到很好的效果!好特征的灵活性在于它允许你可以选择不复杂的模型,同时,运行速度也更快,也更容易理解和维护。好的特征,即使参数不是最优解,模型性能也能表现很好,因此,不需要太多时间去寻找最优参数,大大的降低了模型的复杂度,使模型趋向简单。模型的性能包括模型的效果,执行的效率及模型的可解释性。特征工程的最终目的就是提升模型的性能。
1)特征工程的流程
特征工程到底是什么?可以参考知乎上这位大佬的回答:https://www.zhihu.com/question/29316149/answer/110159647
另外知乎上一些其他人的回答也不错往下翻。建议结合大佬们的理解阅读,多看一些加深理解。大佬们的基本框架就是这样的:
预处理: 无量纲化,对定量特征二值化,对定性特征哑编码,数据变换
特征选择: Filter(过滤)、Wrapper(包裹)、Embedded(嵌入)
降维: 主成分分析法(PCA)、线性判别分析法(LDA)
总结了一下,特征工程基本分成两部分:特征构造(特征生成)和特征选择(特征提取)
首先是特征构造,区别于数据的预处理,这部分可以归纳为“数据”的“编码化”、“无量纲化”
① 无量纲化:数据的标准归一化,对于后续的训练速度和模型的准确性有很大作用,都可以用sklearn包实现,选择合适的方法也是一门学问。
② 编码:分为二值化编码,以及著名的独热(one-hot)编码又称哑编码。处理的对象是我们上游工作流程得到的DF对象,字段内容一般是,非数值型(文本)、离散数值、连续型数值。比如说非数值型的特征此处要进行处理了,模型不能识别非数字的东西,此处一般指的是文字型字段。例如性别{‘男’,‘女’},可以设置为{‘男’:0,‘女’:1},这不是二值化处理。需要说明的是,对于性别这一类的在DataFrame对象中可以用map函数进行处理,十分方便,具体可见下面的代码。除了文字型字段,若是离散的、大小无意义的数字的字段,也需独热处理。在面对大量独热编码时,一个一个用map函数十分不便,而用sklearn上的OneHotEncoder() 会将DF对象变为数组,无法后续处理,也不便于观察特征的名字(当然你可以把这一步放到最后),同样sklearn的无量纲化操作也是这样,破坏美丽的DF数据结构。
③ 特征构造
数据变换,明显也使得数据无量纲,需要注意的是数据变换的本质上是什么呢?没错,实际上就是构造新特征。sklearn里实现了PolynomialFeatures 以及 FunctionTransformer,一个是多项式特征,一个是函数变换。
特征组合,基本利用简单的四则运算,但是一般基于对问题专业知识的理解,对现有几个字段加以组合生成新的特征。
此处对特征构造总结一下。编码(数值规约)是对字段内容(离散型、文本)的特征化,而数据变换则是创造新的特征,方法除了多项式的,函数变换的,四则运算也是最基本的手段。此时,我们得到的‘数据’更像是一些高维的‘特征’了,也许我们只有40个字段,经过这个阶段的处理可以有1000个特征(因为各种函数变换,你想有多少特征都可以)。这就是这一阶段的目的,但是没有特征筛选的支撑这一工作也毫无意义,喂过多的特征会使模型准确性下降。下面我们认识一下特征选择。
① 基于指标的筛选:
大佬的文章中介绍了方差选择法(VarianceThreshold)、相关系数法(pearsonr)、卡方检验法(chi2)和互信息法(MINE),辅助使用SelectKBest()工具依据每个特征的指标选出K个最佳特征,相关系数只能评价线性关系,而卡方检验和互信息可以找到更多有用的特征,鄙人在比赛中辅助使用了互信息和相关系数,并没有完整的应用流程,还需在实践中加强。
② 基于模型的筛选:
特征递归消除: RFE(estimator, n_features_to_select, step, estimator_params, verbose)
嵌入式方法,使用SelectFromModel(),模型一般是L1正则化的逻辑回归模型及基于树的模型如GBDT、RF,具体使用参考大佬的文章中的例子,更多的还是自己亲自在实践中使用。
要注意SelectFromModel(LogisticRegression(penalty=“l1”, C=0.1))这样的是不稳定的,这里向大家推荐sklearn.linear_model的两个方法:
随机lasso回归 RandomizedLasso(alpha=‘aic’, scaling=.5, sample_fraction=.75,
n_resampling=200, selection_threshold=.25,
fit_intercept=True, verbose=False, normalize=True, precompute=‘auto’,
max_iter=500, eps=np.finfo(np.float).eps, random_state=None,
n_jobs=1, pre_dispatch=‘3*n_jobs’, memory=None)
随机逻辑回归 RandomizedLogisticRegression(C=1, scaling=.5, sample_fraction=.75,
n_resampling=200, selection_threshold=.25, tol=1e-3,
fit_intercept=True, verbose=False, normalize=True,
random_state=None, n_jobs=1, pre_dispatch='3*n_jobs', memory=None)
③ 降维:当特征选择完成后,可以直接训练模型了,但是可能由于特征矩阵过大,导致计算量大,训练时间长的问题,因此降低特征矩阵维度也是必不可少的。L1的正则也是一种降维。PCA是为了让映射后的样本具有最大的发散性;而LDA是为了让映射后的样本有最好的分类性能。与筛选不同的是,筛选是舍弃掉某些特征、保留一些特征,而降维后,留下的维度已不再是原来的任一特征,类似于特征之间作了复杂的变换和函数运算,因此降维的过程是新特征生成。但是将降维归到特征选择中,大概因为这一般是调用模型前的最后一步了,一般还是认为这是在筛选特征而不是构造特征。
总结如下:(加上随机lasso)
特征工程流程归纳:
无量纲化(标准归一化)→ 编码 → 特征构造 → 特征筛选 → 降维(如果维度大)
实际上,特征构造和特征选择是反复迭代的关系。
特征工程到底是什么:https://www.zhihu.com/question/29316149/answer/252391239
参考博客:https://blog.csdn.net/xutiantian1412/article/details/79379716
以下贴上自己的代码:
解释一下第37行代码,数字5是加的权重,认为地铁的重要性比公交车大,这个5也可以改其他值,主要就是为了看怎么设置才能使得我们的模型最好,data[‘subwayStationNum’] / data[‘subwayStationNum’].mean() 这一步是为了去量纲
groupby方法生成统计特征,不知道groupy的用法的同学可以参考链接https://www.sogou.com/sie?hdq=AQxRG-4493&query=pandas%E7%9A%84groupby%E7%9A%84%E7%94%A8%E6%B3%95&ie=utf8点击第一个就好,因为是微信链接,直接给微信链接会失效。
聚类方法
log平滑
特征选择
相关系数法
Wrapper
Embedded
基于惩罚项的特征选择法
Lasso(l1)和Ridge(l2)
关于这一部分的内容,建议每一步都要搞清楚为什么要这么做,还有没有其他可以代替的,特征选择本就是一个比较玄学的内容,有时候需要根据经验值来判断,有时候又要根据你的数据来选择。