机器学习笔记六——特征工程之数据预处理

特征工程之数据预处理

  • 1、 处理缺失值
  • 2、 处理异常值
    • 2.1 异常值检测
    • 2.2异常值处理
  • 3、离散特征的连续化处理
  • 4、连续特征的离散化处理
  • 5、 处理类别不平衡问题
  • 6、 图片数据扩充

数据预处理
首先需要对数据进行预处理,一般常用的两种数据类型:

  • 结构化数据。 结构化数据可以看作是关系型数据库的一张表,每列都有清晰的定义,包含了数值型和类别型两种基本类型;每一行数据表示一个样本的信息。

  • 非结构化数据。 主要是文本、图像、音频和视频数据,其包含的信息无法用一个简单的数值表示,也没有清晰的类别定义,并且每个数据的大小互不相同。

1、 处理缺失值

数据的缺失主要包括记录的缺失和记录中某个字段信息的缺失,两者都会造成分析结果的不准确。

缺失值产生的原因

  • 信息暂时无法获取,或者获取信息的代价太大。

  • 信息被遗漏,人为的输入遗漏或者数据采集设备的遗漏。

  • 属性不存在,在某些情况下,缺失值并不意味着数据有错误,对一些对象来说某些属性值是不存在的,如未婚者的配偶姓名、儿童的固定收入等。

缺失值的影响

  • 数据挖掘建模将丢失大量的有用信息。

  • 数据挖掘模型所表现出的不确定性更加显著,模型中蕴含的规律更难把握。

  • 包含空值的数据会使建模过程陷入混乱,导致不可靠的输出。

缺失值的处理方法

1、 直接使用含有缺失值的特征:当仅有少量样本缺失该特征的时候可以尝试使用;

2、 删除含有缺失值的特征:这个方法一般适用于大多数样本都缺少该特征,且仅包含少量有效值是有效的;

3、 插值补全缺失值

最常使用的还是第三种插值补全缺失值的做法,这种做法又可以有多种补全方法。

1. 均值/中位数/众数补全

如果样本属性的距离是可度量的,则使用该属性有效值的平均值来补全;

如果样本属性的距离不可度量,则可以采用众数或者中位数来补全。

2. 同类均值/中位数/众数补全

对样本进行分类后,根据同类其他样本该属性的均值补全缺失值,当然同第一种方法类似,如果均值不可行,可以尝试众数或者中位数等统计数据来补全。

3. 固定值补全

利用固定的数值补全缺失的属性值。

4. 建模预测

利用机器学习方法,将缺失属性作为预测目标进行预测,具体为将样本根据是否缺少该属性分为训练集和测试集,然后采用如回归、决策树等机器学习算法训练模型,再利用训练得到的模型预测测试集中样本的该属性的数值。

这个方法根本的缺陷是如果其他属性和缺失属性无关,则预测的结果毫无意义;但是若预测结果相当准确,则说明这个缺失属性是没必要纳入数据集中的;一般的情况是介于两者之间。

5. 高维映射

将属性映射到高维空间,采用独热码编码(one-hot)技术。将包含 K 个离散取值范围的属性值扩展为 K+1 个属性值,若该属性值缺失,则扩展后的第 K+1 个属性值置为 1。

这种做法是最精确的做法,保留了所有的信息,也未添加任何额外信息,若预处理时把所有的变量都这样处理,会大大增加数据的维度。这样做的好处是完整保留了原始数据的全部信息、不用考虑缺失值;缺点是计算量大大提升,且只有在样本量非常大的时候效果才好。

6. 多重插补

多重插补认为待插补的值是随机的,实践上通常是估计出待插补的值,再加上不同的噪声,形成多组可选插补值,根据某种选择依据,选取最合适的插补值。

7. 压缩感知和矩阵补全

压缩感知通过利用信号本身所具有的稀疏性,从部分观测样本中回复原信号。压缩感知分为感知测量和重构恢复两个阶段。

  • 感知测量:此阶段对原始信号进行处理以获得稀疏样本表示。常用的手段是傅里叶变换、小波变换、字典学习、稀疏编码等

  • 重构恢复:此阶段基于稀疏性从少量观测中恢复原信号。这是压缩感知的核心

矩阵补全可以查看知乎上的问题:矩阵补全(matrix completion)的经典算法有哪些?目前比较流行的算法是什么?

8. 手动补全

除了手动补全方法,其他插值补全方法只是将未知值补以我们的主观估计值,不一定完全符合客观事实。在许多情况下,根据对所在领域的理解,手动对缺失值进行插补的效果会更好。但这种方法需要对问题领域有很高的认识和理解,要求比较高,如果缺失数据较多,会比较费时费力。

9. 最近邻补全

寻找与该样本最接近的样本,使用其该属性数值来补全。

2、 处理异常值

异常值分析是检验数据是否有录入错误以及含有不合常理的数据。忽视异常值的存在是十分危险的,不加剔除地把异常值包括进数据的计算分析过程中,对结果会产生不良影响。

异常值是指样本中的个别值,其数值明显偏离其余的观测值。异常值也称为离群点,异常值分析也称为离群点分析。

2.1 异常值检测

1.简单统计:

比如利用pandas库的**describe()**方法观察数据的统计性描述,或者简单使用散点图也能观察到异常值的存在,如下图所示:

机器学习笔记六——特征工程之数据预处理_第1张图片
2. 3∂原则:

这个原则有个条件:**数据需要服从正态分布。**在 3∂ 原则下,异常值如超过 3 倍标准差,那么可以将其视为异常值。正负3∂ 的概率是 99.7%,那么距离平均值 3∂ 之外的值出现的概率为 P(|x-u| > 3∂) <= 0.003,属于极个别的小概率事件。如果数据不服从正态分布,也可以用远离平均值的多少倍标准差来描述。如下图所示:

机器学习笔记六——特征工程之数据预处理_第2张图片
3.箱型图

这种方法是利用箱型图的四分位距(IQR)对异常值进行检测,也叫Tukey‘s test。箱型图的定义如下:

机器学习笔记六——特征工程之数据预处理_第3张图片

四分位距(IQR)就是上四分位与下四分位的差值。而我们通过IQR的1.5倍为标准,规定:超过上四分位+1.5倍IQR距离,或者下四分位-1.5倍IQR距离的点为异常值。 下面是Python中的代码实现,主要使用了numpy的percentile方法。

Percentile = np.percentile(df['length'],[0,25,50,75,100])
IQR = Percentile[3] - Percentile[1]
UpLimit = Percentile[3]+ageIQR*1.5
DownLimit = Percentile[1]-ageIQR*1.5

也可以使用seaborn的可视化方法boxplot来实现:

f,ax=plt.subplots(figsize=(10,8))
sns.boxplot(y='length',data=df,ax=ax)
plt.show()

更多方法见特征工程之数据预处理(下)

2.2异常值处理

  • 删除含有异常值的记录:直接将含有异常值的记录删除;

  • 视为缺失值: 将异常值视为缺失值,利用缺失值处理的方法进行处理;

  • 平均值修正:可用前后两个观测值的平均值修正该异常值;

  • 不处理:直接在具有异常值的数据集上进行数据挖掘;

将含有异常值的记录直接删除的方法简单易行,但缺点也很明显,在观测值很少的情况下,这种删除会造成样本量不足,可能会改变变量的原有分布,从而造成分析结果的不准确。视为缺失值处理的好处是可以利用现有变量的信息,对异常值(缺失值)进行填补。

在很多情况下,要先分析异常值出现的可能原因,在判断异常值是否应该舍弃,如果是正确的数据,可以直接在具有异常值的数据集上进行挖掘建模。

3、离散特征的连续化处理

(1)独热编码(one-hot encoding)(哑变量)

\quad \quad 处理方法比较简单,比如某特征的取值是高,中和低,那么我们就可以创建三个取值为0或者1的特征,将高编码为1,0,0,中编码为0,1,0,低编码为0,0,1。也就是说,之前的一个特征被我们转化为了三个特征。

from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder

(2)特征嵌入(embedding)
\quad \quad 对于类别特征的处理,最常见的思路是转为one-hot编码,当然这种处理方式比较粗暴,在许多算法里效果也不是很好。当类别很多时,独热编码(One-hot encoding)向量是高维且稀疏的,大数据集下这种方法的计算效率是很低的。

\quad \quad 利用神经网络中的embedding层得到的结果,来作为原来类别特征的替换,然后用于训练其它模型。Keras文档里是这么写embedding的:“把正整数(索引)转换为固定大小的稠密向量”。下面举例说明Embedding的过程:

以性别、星期、居住城市、这3个类别特征为例,它们需要经过如下步骤:

  • 步骤一:分别做one-hot编码,即 Gender=Male∈​{男、女}表示成[1,0],week=Wednesday表示成[0, 0, 1, 0, 0, 0, 0],City=Zhengzhou​∈​{北京、深圳、郑州} 表示成[0, 0,1];

  • 步骤二:将所有的one-hot编码特征首尾相连,构成新的输入向量x=[1,0,0,0,1,0,0,0,0,0,0,1]​

  • 步骤三:将输入向量和权重做矩阵乘法运算,得到当前网络层的输出;

图像化表示如下,
机器学习笔记六——特征工程之数据预处理_第4张图片

4、连续特征的离散化处理

\quad \quad 连续特征的离散化就是在数据的取值范围内设定若干个离散的划分点,将取值范围划分为一些离散化的区间,最后用不同的符号或整数值代表落在每个子区间中的数据值。

\quad \quad 首先要确定分类数,然后将连续特征值映射到这些分类值(等宽法、等频法、一维聚类)。

(1)根据阈值进行分组

\quad \quad 比如我们根据连续值特征的分位数,将该特征分为高,中和低三个特征。将分位数从0-0.3的设置为低,0.3-0.7的设置为中,0.7-1的设置为高。

(2)基于聚类分析的方法

\quad \quad 一维聚类的方法包括两个步骤,首先将连续特征的值用聚类算法(如K-Means算法)进行聚类,然后再将聚类得到的簇进行处理,合并到一个簇的连续特征值并做同一标记。聚类分析的离散化方法也需要用户指定簇的个数,从而决定产生的区间数。

(3)使用梯度提升树(GDBT)将连续值转化为离散值

\quad \quad 在sklearn中,我们可以用GradientBoostingClassifier的 apply方法很方便的得到样本离散化后的特征,然后使用独热编码即可

5、 处理类别不平衡问题

什么是类别不平衡呢?它是指分类任务中存在某个或者某些类别的样本数量远多于其他类别的样本数量的情况。

比如,一个十分类问题,总共有 10000 个样本,但是类别 1 到 4 分别包含 2000 个样本,剩余 6 个类别的样本数量加起来刚刚 2000 个,即这六个类别各自包含的样本平均数量大约是 333 个,相比前四个类别是相差了 6 倍左右的数量。这种情况就是类别不平衡了。

那么如何解决类别不平衡问题呢?

这里介绍八大解决办法。

1.扩充数据集

首先应该考虑数据集的扩充,在刚刚图片数据集扩充一节介绍了多种数据扩充的办法,而且数据越多,给模型提供的信息也越大,更有利于训练出一个性能更好的模型。

如果在增加小类样本数量的同时,又增加了大类样本数据,可以考虑放弃部分大类数据(通过对其进行欠采样方法)。

2.尝试其他评价指标

一般分类任务最常使用的评价指标就是准确度了,但它在类别不平衡的分类任务中并不能反映实际情况,原因就是即便分类器将所有类别都分为大类,准确度也不会差,因为大类包含的数量远远多于小类的数量,所以这个评价指标会偏向于大类类别的数据。

其他可以推荐的评价指标有以下几种

  • 混淆矩阵:实际上这个也是在分类任务会采用的一个指标,可以查看分类器对每个类别预测的情况,其对角线数值表示预测正确的数量;

  • 精确度(Precision):表示实际预测正确的结果占所有被预测正确的结果的比例,P=TP / (TP+FP)

  • 召回率(Recall):表示实际预测正确的结果占所有真正正确的结果的比例,R = TP / (TP+FN)

  • F1 得分(F1 Score):精确度和召回率的加权平均,F1=2PR / (P+R)

  • Kappa (Cohen kappa)

  • ROC 曲线(ROC Curves):常被用于评价一个二值分类器的优劣,而且对于正负样本分布变化的时候,ROC 曲线可以保持不变,即不受类别不平衡的影响。

其中 TP、FP、TN、FN 分别表示正确预测的正类、错误预测的正类、预测正确的负类以及错误预测的负类。图例如下:

机器学习笔记六——特征工程之数据预处理_第5张图片
实现并可视化混淆矩阵的代码实现:

# 计算混淆矩阵
from sklearn.metrics import confusion_matrix
cnf_matrix = confusion_matrix(y_test,y_pred)
# 混淆矩阵的可视化显示,以下代码可以直接作为模板
import itertools
# cm参数:混淆矩阵,classes参数:类别名称
def plot_confusion_matrix(cm, classes,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    """
    绘制混淆矩阵
    """
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=0)
    plt.yticks(tick_marks, classes)

    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, cm[i, j],
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

3.对数据集进行重采样

可以使用一些策略该减轻数据的不平衡程度。该策略便是采样(sampling),主要有两种采样方法来降低数据的不平衡性。

  • 对小类的数据样本进行采样来增加小类的数据样本个数,即过采样(over-sampling ,采样的个数大于该类样本的个数)。

  • 对大类的数据样本进行采样来减少该类数据样本的个数,即欠采样(under-sampling,采样的次数少于该类样本的个素)。

采样算法往往很容易实现,并且其运行速度快,并且效果也不错。 一些经验法则:

  • 考虑对大类下的样本(超过 1 万、十万甚至更多)进行欠采样,即删除部分样本;

  • 考虑对小类下的样本(不足 1万甚至更少)进行过采样,即添加部分样本的副本;

  • 考虑尝试随机采样与非随机采样两种采样方法;

  • 考虑对各类别尝试不同的采样比例,比一定是 1:1,有时候 1:1 反而不好,因为与现实情况相差甚远;

  • 考虑同时使用过采样与欠采样。

4.尝试人工生成数据样本

一种简单的人工样本数据产生的方法便是,对该类下的所有样本每个属性特征的取值空间中随机选取一个组成新的样本, 即属性值随机采样。

你可以使用基于经验对属性值进行随机采样而构造新的人工样本,或者使用类似朴素贝叶斯方法假设各属性之间互相独立进行采样,这样便可得到更多的数据,但是无法保证属性之前的线性关系(如果本身是存在的)。

有一个系统的构造人工数据样本的方法 SMOTE(Synthetic Minority Over-sampling Technique)。SMOTE 是一种过采样算法,它构造新的小类样本而不是产生小类中已有的样本的副本,即该算法构造的数据是新样本,原数据集中不存在的。

它基于距离度量选择小类别下两个或者更多的相似样本,然后选择其中一个样本,并随机选择一定数量的邻居样本,然后对选择的那个样本的一个属性增加噪声,每次处理一个属性。这样就构造了更多的新生数据。

python 实现的 SMOTE 算法代码地址如下,它提供了多种不同实现版本,以及多个重采样算法。

https://github.com/scikit-learn-contrib/imbalanced-learn

5.尝试不同分类算法

强烈建议不要对待每一个分类都使用自己喜欢而熟悉的分类算法。应该使用不同的算法对其进行比较,因为不同的算法适用于不同的任务与数据。

决策树往往在类别不均衡数据上表现不错。它使用基于类变量的划分规则去创建分类树,因此可以强制地将不同类别的样本分开。目前流行的决策树算法有:C4.5、C5.0、CART和Random Forest等。

6.尝试对模型进行惩罚

你可以使用相同的分类算法,但使用一个不同的角度,比如你的分类任务是识别那些小类,那么可以对分类器的小类样本数据增加权值,降低大类样本的权值(这种方法其实是产生了新的数据分布,即产生了新的数据集),从而使得分类器将重点集中在小类样本身上。

一个具体做法就是,在训练分类器时,若分类器将小类样本分错时额外增加分类器一个小类样本分错代价,这个额外的代价可以使得分类器更加“关心”小类样本。如 penalized-SVM 和 penalized-LDA 算法。

如果你锁定一个具体的算法时,并且无法通过使用重采样来解决不均衡性问题而得到较差的分类结果。这样你便可以使用惩罚模型来解决不平衡性问题。但是,设置惩罚矩阵是一个复杂的事,因此你需要根据你的任务尝试不同的惩罚矩阵,并选取一个较好的惩罚矩阵。

7.尝试一个新的角度理解问题

从一个新的角度来理解问题,比如我们可以将小类的样本作为异常点,那么问题就变成异常点检测与变化趋势检测问题。

异常点检测:即是对那些罕见事件进行识别。如通过机器的部件的振动识别机器故障,又如通过系统调用序列识别恶意程序。这些事件相对于正常情况是很少见的。

变化趋势检测:类似于异常点检测,不同在于其通过检测不寻常的变化趋势来识别。如通过观察用户模式或银行交易来检测用户行为的不寻常改变。

将小类样本作为异常点这种思维的转变,可以帮助考虑新的方法去分离或分类样本。这两种方法从不同的角度去思考,让你尝试新的方法去解决问题。

8.尝试创新

仔细对问题进行分析和挖掘,是否可以将问题划分为多个更小的问题,可以尝试如下方法:

将你的大类压缩成小类;

使用 One Class 分类器(将小类作为异常点);

使用集成方式,训练多个分类器,然后联合这些分类器进行分类;

对于类别不平衡问题,还是需要具体问题具体分析,如果有先验知识可以快速挑选合适的方法来解决,否则最好就是逐一测试每一种方法,然后挑选最好的算法。最重要的还是多做项目,多积累经验,这样遇到一个新的问题,也可以快速找到合适的解决方法。

6、 图片数据扩充

对于图片数据,最常遇到的问题就是训练数据不足的问题。

一个模型所能获取的信息一般来源于两个方面,一个是训练数据包含的信息;另一个就是模型的形成过程中(包括构造、学习、推理等),人们提供的先验信息。

而如果训练数据不足,那么模型可以获取的信息就比较少,需要提供更多的先验信息保证模型的效果。先验信息一般作用来两个方面,一是模型,如采用特定的内在结构(比如深度学习的不同网络结构)、条件假设或添加其他约束条件(深度学习中体现在损失函数加入不同正则项);第二就是数据,即根据先验知识来调整、变换或者拓展训练数据,让其展现出更多的、更有用的信息。

对于图像数据,如果训练数据不足,导致的后果就是模型过拟合问题,即模型在训练样本上的效果不错,但在测试集上的泛化效果很糟糕。过拟合的解决方法可以分为两类:

1、基于模型的方法:主要是采用降低过拟合风险的措施,如简化模型(从卷积神经网络变成逻辑回归算法)、添加约束项以缩小假设空间(如 L1、L2等正则化方法)、集成学习、Dropout方法(深度学习常用方法)等;

2、基于数据的方法: 主要就是数据扩充(Data Augmentation),即根据一些先验知识,在保持特点信息的前提下,对原始数据进行适当变换以达到扩充数据集的效果。具体做法有多种,在保持图像类别不变的前提下,可以对每张图片做如下变换处理。

  • 一定程度内的随机旋转、平移、缩放、裁剪、填充、左右翻转等,这些变换对应着同一个目标在不同角度的观察结果;

  • 对图像中的元素添加噪声扰动,如椒盐噪声、高斯白噪声等;

  • 颜色变换。比如在图像的 RGB 颜色空间进行主成分分析,得到 3 个主成分的特征向量p1,p2,p3以及对应的特征值λ1,λ2,λ3,然后在每个像素的 RGB 值上添加增量[p1,p2,p3]*[a1λ1,a2λ2,a3λ3],其中a1,a2,a3都是均值为 0, 方差较小的高斯分布随机数;

  • 改变图像的亮度、清晰度、对比度、锐度等。

上述数据扩充方法是在图像空间进行变换的,也可以选择先对图像进行特征提取,然后在图像的特征空间进行变换,利用一些通用的数据扩充或者上采样方法,例如 SMOTE(Synthetic Minority Over-sampling Technique)。

此外,最近几年一直比较热门的 GAN,生成对抗网络,它的其中一个应用就是生成图片数据,也可以应用于数据扩充。

最后,还有一种方法可以不需要扩充数据,利用迁移学习的做法,也是如今非常常用的一个方法,微调(Finetuning),即借用在大数据集(如 ImageNet)上预训练好的模型,然后在自己的小数据集上进行微调,这是一种简单的迁移学习,同时也可以快速训练一个效果不错的针对目标类别的新模型。

参考资料:

  • https://mp.weixin.qq.com/s?__biz=MzU5MDY5OTI5MA==&mid=2247483915&idx=1&sn=08dcf6883688639403c5d81b70c1dd57&scene=21#wechat_redirect
  • 百面机器学习
  • https://blog.csdn.net/lc013/article/details/100033144

未完待续

你可能感兴趣的:(#,特征工程,机器学习,特征工程,数据预处理,机器学习)