重要性:

特征工程是比赛中重要的一部分,调参带来的效益往往是有限的,特征工程选取的好坏决定最终的结果。

必要性:

特征工程是和模型结合在一起的,其能更好地表示潜在问题的特征,从而提高机器学习的性能。

特征工程是很低的,容易入门,但是若想精通就需要花费较大的功夫了,正所谓师傅领进门,修行靠个人。

目标:

学习特征工程我们的目的是:对于特征进行进一步分析,并对于数据进行处理。

内容:

本文我将从以下几点介绍我认识的特征工程

  1. 异常处理;
  2. 特征归一化/标准化;
  3. 数据分桶;
  4. 缺失值处理;
  5. 特征构造;
  6. 特征筛选;
  7. 降维。

异常处理

通常有以下几种方法

异常值处理:

通过箱线图,分析并删去异常值

  • 上四分位数Q3 是指数据从小到大排列,取其3/4处位置的分位数
  • 下四分位数Q1 是指数据从小到大排列,取其1/4处位置的分位数
  • IQR = Q3-Q1指的是四分位距,即上四分位数和下四分位数的差值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 给出一个数据异常值处理的函数
def outliers_proc(data, col_name, scale=3):
"""
用于清洗异常值,默认用 box_plot(scale=3)进行清洗
:param data: 接收 pandas 数据格式
:param col_name: pandas 列名
:param scale: 尺度
:return:
"""

def box_plot_outliers(data_ser, box_scale):
"""
利用箱线图去除异常值
:param data_ser: 接收 pandas.Series 数据格式
:param box_scale: 箱线图尺度,
:return:
"""
iqr = box_scale * (data_ser.quantile(0.75) - data_ser.quantile(0.25))
val_low = data_ser.quantile(0.25) - iqr
val_up = data_ser.quantile(0.75) + iqr
rule_low = (data_ser < val_low)
rule_up = (data_ser > val_up)
return (rule_low, rule_up), (val_low, val_up)

data_n = data.copy()
data_series = data_n[col_name]
rule, value = box_plot_outliers(data_series, box_scale=scale)
index = np.arange(data_series.shape[0])[rule[0] | rule[1]]
print("Delete number is: {}".format(len(index)))
data_n = data_n.drop(index)
data_n.reset_index(drop=True, inplace=True)
print("Now column number is: {}".format(data_n.shape[0]))
index_low = np.arange(data_series.shape[0])[rule[0]]
outliers = data_series.iloc[index_low]
print("Description of data less than the lower bound is:")
print(pd.Series(outliers).describe())
index_up = np.arange(data_series.shape[0])[rule[1]]
outliers = data_series.iloc[index_up]
print("Description of data larger than the upper bound is:")
print(pd.Series(outliers).describe())

fig, ax = plt.subplots(1, 2, figsize=(10, 7))
sns.boxplot(y=data[col_name], data=data, palette="Set1", ax=ax[0])
sns.boxplot(y=data_n[col_name], data=data_n, palette="Set1", ax=ax[1])
return data_n

返回..

BOX-COX 转换(处理有偏分布)

将数据转化为正态分布

我们都知道 log 变换 可以使数据在一定程度上符合正态分布,特别是有尾数据分布。

但是…采用这种方法,

  • 较小数据之间的差异将会变大(因为对数函数的斜率很小),而较大数据之间的差异将减少(可能某分布中较大数据的斜率很小)。

  • 如果你拓展了左尾的差异,减少了右尾的差异,结果将是方差恒定、形状对称的正态分布(无论均值大小如何)。

参见【Reference】:使用Box-Cox转换的益处BoxCox 变换方法及其实现运用

返回..

长尾截断

对于连续型数值特征,有时精度太高可能只是噪声,并不具备太多的信息,也使得特征维度急剧上升。因此可以保留一定的精度,之后当作类别特征进行处理。对于长尾的数据,可以先进行对数缩放,再进行精度截断,之后可以当做类别变量做二值化处理。

在这里插入图片描述

特征归一化 / 标准化

思想:

  • 标准化(转换为标准正态分布);
  • 归一化(映射到 [0,1] 区间); - Sigmoid 函数
  • 针对幂律分布,可以采用公式:$log( \frac{1+x}{1+median})$

算法:

  1. Z-score
  2. min-max
  3. 行归一化

特征尺度不一致需要标准化,以下算法会受尺度影响

  1. KNN,依赖距离
  2. K-meas
  3. 逻辑回归,支持向量机,神经网络等如果使用梯度下降来学习权重;
  4. 主成分分析,特征向量偏向于较大的列

在机器学习 Pipeline 中使用归一化

数据分桶

Q:

为什么要做数据分桶呢?

A:

  1. 离散后稀疏向量内积乘法运算速度更快,计算结果也方便存储,容易扩展;
  2. 离散后的特征对异常值更具鲁棒性,如 age>30 为 1 否则为 0,对于年龄为 200 的也不会对模型造成很大的干扰;
  3. LR 属于广义线性模型,表达能力有限,经过离散化后,每个变量有单独的权重,这相当于引入了非线性,能够提升模型的表达能力,加大拟合;
  4. 离散后特征可以进行特征交叉,提升表达能力,由 M+N 个变量编程 M*N 个变量,进一步引入非线形,提升了表达能力;
  5. 特征离散后模型更稳定,如用户年龄区间,不会因为用户年龄长了一岁就变化
  6. e.t.c 当然还有很多原因,LightGBM 在改进 XGBoost 时就增加了数据分桶,增强了模型的泛化性
  • 等频分桶;
  • 等距分桶;
  • Best-KS 分桶(类似利用基尼指数进行二分类);
  • 卡方分桶;

参见【Reference】:浅谈微视推荐系统中的特征工程

缺失值处理

  • 不处理(针对类似 XGBoost 等树模型);
  • 删除(缺失数据太多);
  • 插值补全,包括均值/中位数/众数/建模预测/多重插补/压缩感知补全/矩阵补全等;
  • 分箱,缺失值一个箱;

在这里插入图片描述

参见【Reference】:机器学习中如何处理缺失数据?数据缺失值的4种处理方法

特征构造

  • 构造统计量特征,报告计数、求和、比例、标准差等;
  • 时间特征,包括相对时间和绝对时间,节假日,双休日等;
  • 地理信息,包括分箱,分布编码等方法;
  • 非线性变换,包括 log/ 平方/ 根号等;
  • 特征组合,特征交叉;

训练集和测试集放在一起,方便构造特征 【contact】

1
2
3
Train_data['train']=1
Test_data['train']=0
data = pd.concat([Train_data, Test_data], ignore_index=True)

检查空数据

可以选择删除也可以留下

  • 删除缺失数据占总样本量过大,不建议删去;
  • 当要交到xgboost模型中处理时,不必要。

特征的构造视模型数量而定

不同模型对数据集的要求不同,需要分开构造

特征归一化 / 标准化和数据分桶通常体现在特征构造的过程中

特征筛选

  • 过滤式(filter):先对数据进行特征选择,然后在训练学习器,常见的方法有 Relief / 方差选择法 / 相关系数法 / 卡方检验法 / 互信息法;
  • 包裹式(wrapper):直接把最终将要使用的学习器的性能作为特征子集的评价准则,常见方法有 LVM(Las Vegas Wrapper) ;
  • 嵌入式(embedding):结合过滤式和包裹式,学习器训练过程中自动进行了特征选择,常见的有 lasso 回归;

参见【Reference】:如何进行特征选择(理论篇)

降维

采用某种映射方法,将原高维空间中的数据点映射到低维度的空间中

降维本质上即是学习一个映射函数 $f : x->y$【其中x是原始数据点的表达,目前最多使用向量表达形式。 y是数据点映射后的低维向量表达,通常y的维度小于x的维度(当然提高维度也是可以的)】

$f$ 可能是显式的或隐式的、线性的或非线性的

目的:

  • 减少冗余信息所造成的误差,提高识别(或其他应用)的精度;
  • 希望通过降维算法来寻找数据内部的本质结构特征

方法:

  • PCA / LDA / ICA;
  • 特征选择也是一种降维。

参见【Reference】:机器学习四大降维方法