概述
3.1 特征工程目标
- 对于特征进行进一步分析,并对于数据进行处理
- 完成关于特征工程的分析,并针对数据进行一些图表或文字总结
3.2 内容介绍
常见的特征工程包括:
- 异常处理:
- 通过箱线图(或3-Sigma)分析删除异常值
- BOX-COX转换(处理有偏分布)
- 长尾截断
- 特征归一化/标准化:
- 标准化(转换为标准正态分布)
- 归一化(转换到[0,1]区间)
- 针对幂律分布,可以采用公式
- 数据分桶:
- 等频分桶
- 等距分桶
- Best-KS分桶(类似利用基尼指数进行二分类)
- 卡方分桶
- 缺失值处理:
- 不处理(针对类似XGBoost等树模型)
- 删除(删除数据太多)
- 插值补全,包括均值/中位数/众数/建模预测/多重插补/压缩感知补全/矩阵补全等
- 分箱,缺失值一个箱
- 特征构造:
- 构造统计量特征,报告计数,求和,比例,标准差等
- 时间特征,包括相对时间和绝对时间,节假日,双休日等
- 地理信息,包括分箱,分布编码等方法
- 非线性变换,包括log /平方/根号等
- 特征组合,特征交叉
- 仁者见仁,智者见智
- 特征筛选
- 过滤式(filter):先对数据进行特征选择,然后在训练学习器,常见的方法有救济/方差选择发/相关系数法/卡方检验法/互信息法
- 包裹式(wrapper):直接把最终将要使用的学习器的性能作为特征子集的评价参数,常见方法有----- LVM(拉斯维加斯包装)
- 嵌入式(embedding):结合过滤式和包裹式,学习器训练过程中自动进行了特征选择,常见的有套索回归
- 降维
- PCA / LDA / ICA
- 特征选择也是一种降维
3.3 代码示例
3.3.0 导入数据
3.3.1 删除异常值
这里我写了一个异常值处理的代码,可以随便调用。
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
我们可以删掉一些异常数据,以 power 为例。
3.3.2 特征构造
- 将训练集和测试集放一起,方便构造特征
- 构造使用时间:data[‘creatDate’] - data[‘regDate’]
- 构造城市信息
- 计算某品牌的销售统计量
- 数据分桶
数据分桶 以 power 为例,这时候我们的缺失值也进桶了.为什么要做数据分桶呢,原因有很多:
- 离散后稀疏向量内积乘法运算速度更快,计算结果也方便存储,容易扩展;
- 离散后的特征对异常值更具鲁棒性,如 age>30 为 1 否则为 0,对于年龄为 200 的也不会对模型造成很大的干扰;
- LR 属于广义线性模型,表达能力有限,经过离散化后,每个变量有单独的权重,这相当于引入了非线性,能够提升模型的表达能力,加大拟合;
- 离散后特征可以进行特征交叉,提升表达能力,由 M+N 个变量编程 M*N 个变量,进一步引入非线形,提升了表达能力;
- 特征离散后模型更稳定,如用户年龄区间,不会因为用户年龄长了一岁就变化.
- 当然还有很多原因,LightGBM 在改进 XGBoost 时就增加了数据分桶,增强了模型的泛化性
- 数据归一化
我们刚刚已经对 train进行异常值处理了,但是现在还有这么奇怪的分布是因为 test中的 power 异常值,所以我们其实刚刚 train中的 power异常值不删为好,可以用长尾分布截断来代替。
- 对类别特征进行one-hot编码
data = pd.get_dummies(data, columns = ['model','brand','bodyType','fuelType','gearbox','notRepairedDamage','power_bin'])
3.3.3 特征筛选
- 过滤式
- 包裹式
- 嵌入式
3.4 经验总结
- 特征工程是比赛中最至关重要的的一块,特别的传统的比赛,大家的模型可能都差不多,调参带来的效果增幅是非常有限的,但特征工程的好坏往往会决定了最终的排名和成绩。
- 特征工程的主要目的还是在于将数据转换为能更好地表示潜在问题的特征,从而提高机器学习的性能。比如,异常值处理是为了去除噪声,填补缺失值可以加入先验知识等。
- 特征构造也属于特征工程的一部分,其目的是为了增强数据的表达。
- 有些比赛的特征是匿名特征,这导致我们并不清楚特征相互直接的关联性,这时我们就只有单纯基于特征进行处理,比如装箱,groupby,agg 等这样一些操作进行一些特征统计,此外还可以对特征进行进一步的 log,exp 等变换,或者对多个特征进行四则运算(如上面我们算出的使用时长),多项式组合等然后进行筛选。由于特性的匿名性其实限制了很多对于特征的处理,当然有些时候用 NN 去提取一些特征也会达到意想不到的良好效果。
- 对于知道特征含义(非匿名)的特征工程,特别是在工业类型比赛中,会基于信号处理,频域提取,丰度,偏度等构建更为有实际意义的特征,这就是结合背景的特征构建,在推荐系统中也是这样的,各种类型点击率统计,各时段统计,加用户属性的统计等等,这样一种特征构建往往要深入分析背后的业务逻辑或者说物理原理,从而才能更好的找到 magic。
- 当然特征工程其实是和模型结合在一起的,这就是为什么要为 LR NN 做分桶和特征归一化的原因,而对于特征的处理效果和特征重要性等往往要通过模型来验证。
- 总的来说,特征工程是一个入门简单,但想精通非常难的一件事。
最后
以上就是和谐水池为你收集整理的天池二手车价格预测-特征工程的全部内容,希望文章能够帮你解决天池二手车价格预测-特征工程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复