特征工程基础知识总结概述

文章目录

    • 异常值处理
    • 缺失值处理
    • 数据分桶
    • 数据转换
    • 特征构造
    • 特征选择
      • 过滤式
      • 包裹式
      • 嵌入式
    • PCA降维技术

特征工程(Feature Engineering)对特征进行进一步分析,并对数据进行处理。常见的特征工程包括:异常值处理、缺失值处理、数据分桶、特征处理、特征构造、特征筛选及降维等。

异常值处理

  • 常用的异常值处理操作包括BOX-COX转换(处理有偏分布),箱线图分析删除异常值长尾截断等方式, 当然这些操作一般都是处理数值型的数据。
    • box-cox转换,一般是用于连续的变量不满足正态的时候.

缺失值处理

关于缺失值处理的方式, 有几种情况

  • 不处理(这是针对xgboost等树模型),有些模型有处理缺失的机制,所以可以不处理
  • 如果缺失的太多,可以考虑删除该列
  • 插值补全(均值,中位数,众数,建模预测,多重插补等)
  • 分箱处理,缺失值一个箱。

下面整理几种填充值的方式:

# 删除重复值
data.drop_duplicates()
# dropna()可以直接删除缺失样本,但是有点不太好

# 填充固定值
train_data.fillna(0, inplace=True) # 填充 0
data.fillna({0:1000, 1:100, 2:0, 4:5})   # 可以使用字典的形式为不用列设定不同的填充值

train_data.fillna(train_data.mean(),inplace=True) # 填充均值
train_data.fillna(train_data.median(),inplace=True) # 填充中位数
train_data.fillna(train_data.mode(),inplace=True) # 填充众数

train_data.fillna(method='pad', inplace=True) # 填充前一条数据的值,但是前一条也不一定有值
train_data.fillna(method='bfill', inplace=True) # 填充后一条数据的值,但是后一条也不一定有值

"""插值法:用插值法拟合出缺失的数据,然后进行填充。"""
for f in features: 
    train_data[f] = train_data[f].interpolate()

train_data.dropna(inplace=True)

"""填充KNN数据:先利用knn计算临近的k个数据,然后填充他们的均值"""
from fancyimpute import KNN
train_data_x = pd.DataFrame(KNN(k=6).fit_transform(train_data_x), columns=features)

数据分桶

连续值经常离散化或者分离成“箱子”进行分析, 为什么要做数据分桶呢?

  • 离散后稀疏向量内积乘法运算速度更快,计算结果也方便存储,容易扩展;
  • 离散后的特征对异常值更具鲁棒性,如 age>30 为 1 否则为 0,对于年龄为 200 的也不会对模型造成很大的干扰;
  • LR 属于广义线性模型,表达能力有限,经过离散化后,每个变量有单独的权重,这相当于引入了非线性,能够提升模型的表达能力,加大拟合;
  • 离散后特征可以进行特征交叉,提升表达能力,由 M+N 个变量编程 M*N 个变量,进一步引入非线形,提升了表达能力;
  • 特征离散后模型更稳定,如用户年龄区间,不会因为用户年龄长了一岁就变化

当然还有很多原因,LightGBM 在改进 XGBoost 时就增加了数据分桶,增强了模型的泛化性。现在介绍数据分桶的方式:

  • 等频分桶
  • 等距分桶
  • Best-KS分桶(类似利用基尼指数进行二分类)
  • 卡方分桶

最好将数据分桶的特征作为新一列的特征,不要把原来的数据给替换掉。

数据分桶的一个例子

# 连续值经常离散化或者分离成“箱子”进行分析。
# 假设某项研究中一组人群的数据,想将他们进行分组,放入离散的年龄框中
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
# 如果按年龄分成18-25, 26-35, 36-60, 61以上的若干组,可以使用pandas中的cut
bins = [18, 25, 35, 60, 100]         # 定义箱子的边
cats = pd.cut(ages, bins)
print(cats)   # 这是个categories对象    通过bin分成了四个区间, 然后返回每个年龄属于哪个区间
# codes属性
print(cats.codes)    #  这里返回一个数组,指明每一个年龄属于哪个区间
print(cats.categories)
print(pd.value_counts(cats))   # 返回结果是每个区间年龄的个数

# 与区间的数学符号一致, 小括号表示开放,中括号表示封闭, 可以通过right参数改变
print(pd.cut(ages, bins, right=False))

# 可以通过labels自定义箱名或者区间名
group_names = ['Youth', 'YonngAdult', 'MiddleAged', 'Senior']
data = pd.cut(ages, bins, labels=group_names)
print(data)
print(pd.value_counts(data))

# 如果将箱子的边替代为箱子的个数,pandas将根据数据中的最小值和最大值计算出等长的箱子
data2 = np.random.rand(20)
print(pd.cut(data2, 4, precision=2))   # precision=2 将十进制精度限制在2位

# qcut是另一个分箱相关的函数, 基于样本分位数进行分箱。取决于数据的分布,使用cut不会使每个箱子具有相同数据数量的数据点,而qcut,使用
# 样本的分位数,可以获得等长的箱
data3 = np.random.randn(1000)   # 正太分布
cats = pd.qcut(data3, 4)
print(pd.value_counts(cats))
  • 结果
    特征工程基础知识总结概述_第1张图片

数据转换

数据转换的方式有

  • 数据归一化(MinMaxScaler):数值的取值范围相差很大
  • 标准化(StandardScaler);
  • 对数变换(log1p);
  • 转换数据类型(astype);
  • 独热编码(OneHotEncoder):类别特征某些需要独热编码一下
  • 标签编码(LabelEncoder);
  • 修复偏斜特征(boxcox1p)等。

特征构造

在特征构造的时候,需要借助一些背景知识,遵循的一般原则就是需要发挥想象力,尽可能多的创造特征,不用先考虑哪些特征可能好,可能不好,先弥补这个广度。特征构造的时候需要考虑数值特征,类别特征,时间特征。

  • 对于数值特征,一般会尝试一些它们之间的加减组合(当然不要乱来,根据特征表达的含义)或者提取一些统计特征
  • 对于类别特征,我们一般会尝试之间的交叉组合,embedding也是一种思路
  • 对于时间特征,这一块又可以作为一个大专题来学习,在时间序列的预测中这一块非常重要,也会非常复杂,需要就尽可能多的挖掘时间信息,会有不同的方式技巧。当然在这个比赛中涉及的实际序列数据有一点点,不会那么复杂。

特征选择

特征选择主要有两个功能

  • 减少特征数量、降维,使模型泛化能力更强,减少过拟合
  • 增强对特征和特征值之间的理解

通常来说,从两个方面考虑来选择特征

  • 特征是否发散:如果一个特征不发散,例如方差接近于0,也就是说样本在这个特征上基本上没有差异,这个特征对于样本的区分并没有什么用。
  • 特征与目标的相关性:这点比较显见,与目标相关性高的特征,应当优选选择。

根据特征选择的形式又可以将特征选择方法分为3种

  • Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。
  • Wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。
  • Embedded:嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于Filter方法,但是是通过训练来确定特征的优劣。

过滤式

  • 主要思想: 对每一维特征“打分”,即给每一维的特征赋予权重,这样的权重就代表着该特征的重要性,然后依据权重排序。先进行特征选择,然后去训练学习器,所以特征选择的过程与学习器无关。相当于先对特征进行过滤操作,然后用特征子集来训练分类器。
  • 主要方法
    • 移除低方差的特征;
    • 相关系数排序,分别计算每个特征与输出值之间的相关系数,设定一个阈值,选择相关系数大于阈值的部分特征;
    • 利用假设检验得到特征与输出值之间的相关性,方法有比如卡方检验、t检验、F检验等。
    • 互信息,利用互信息从信息熵的角度分析相关性。

为大家提供一些有价值的小tricks

  • 对于数值型特征,方差很小的特征可以不要,因为太小没有什么区分度,提供不了太多的信息,对于分类特征,也是同理,取值个数高度偏斜的那种可以先去掉。
  • 根据与目标的相关性等选出比较相关的特征(当然有时候根据字段含义也可以选)
  • 卡方检验一般是检查离散变量与离散变量的相关性,当然离散变量的相关性信息增益和信息增益比也是不错的选择(可以通过决策树模型来评估来看),person系数一般是查看连续变量与连续变量的线性相关关系。

包裹式

  • 单变量特征选择方法独立的衡量每个特征与响应变量之间的关系,另一种主流的特征选择方法是基于机器学习模型的方法。有些机器学习方法本身就具有对特征进行打分的机制,或者很容易将其运用到特征选择任务中,例如回归模型,SVM,决策树,随机森林等等。
  • 主要思想:包裹式从初始特征集合中不断的选择特征子集,训练学习器,根据学习器的性能来对子集进行评价,直到选择出最佳的子集。包裹式特征选择直接针对给定学习器进行优化。
  • 主要方法:递归特征消除算法, 基于机器学习模型的特征排序
  • 优缺点
    • 优点:从最终学习器的性能来看,包裹式比过滤式更好;
    • 缺点:由于特征选择过程中需要多次训练学习器,因此包裹式特征选择的计算开销通常比过滤式特征选择要大得多。

嵌入式

  • 在过滤式和包裹式特征选择方法中,特征选择过程与学习器训练过程有明显的分别。而嵌入式特征选择在学习器 训练过程中自动地进行特征选择。嵌入式选择最常用的是L1正则化与L2正则化。在对线性回归模型加入两种正则化方法后,他们分别变成了岭回归与Lasso回归。

  • 主要思想:在模型既定的情况下学习出对提高模型准确性最好的特征。也就是在确定模型的过程中,挑选出那些对模型的训练有重要意义的特征。

  • 主要方法:简单易学的机器学习算法–岭回归(Ridge Regression),就是线性回归过程加入了L2正则项。

  • L1正则化有助于生成一个稀疏权值矩阵,进而可以用于特征选择

  • L2正则化在拟合过程中通常都倾向于让权值尽可能小,最后构造一个所有参数都比较小的模型。因为一般认为参 数值小的模型比较简单,能适应不同的数据集,也在一定程度上避免了过拟合现象。可以设想一下对于一个线性 回归方程,若参数很大,那么只要数据偏移一点点,就会对结果造成很大的影响;但如果参数足够小,数据偏移 得多一点也不会对结果造成什么影响,专业一点的说法是『抗扰动能力强』。

PCA降维技术

  • 通过上面的特征选择部分,可以选出更好的分析特征,但是如果这些特征维度仍然很高怎么办?
  • 如果数据特征维度太高,首先计算很麻烦,其次增加了问题的复杂程度,分析起来也不方便。这时候就会想是不是再去掉一些特征就好了呢?但是这个特征也不是凭自己的意愿去掉的,因为盲目减少数据的特征会损失掉数据包含的关键信息,容易产生错误的结论,对分析不利。
  • 所以想找到一个合理的方式,既可以减少需要分析的指标,而且尽可能多的保持原来数据的信息,PCA就是这个合理的方式之一。 但要注意一点, 特征选择是从已存在的特征中选取携带信息最多的,选完之后的特征依然具有可解释性,而PCA,将已存在的特征压缩,降维完毕后不是原来特征的任何一个,也就是PCA降维之后的特征我们根本不知道什么含义了。

你知道的越多,你不知道的越多。
有道无术,术尚可求,有术无道,止于术。
如有其它问题,欢迎大家留言,我们一起讨论,一起学习,一起进步

你可能感兴趣的:(机器学习)