「文末高能」
编辑 | 哈比
数据预处理,可以说是数据挖掘过程中的一个最重要的步骤, “garbage in, garbage out” 非常适用于形容数据挖掘和机器学习,输入的数据烂,输出的模型效果也会很烂。
数据的采集过程中通常会出现一些不可避免的失误,无论是人工录入、通过传感器获得还是从网页上爬取的数据,都会需要对这些错误进行一些处理。
最常见的错误包括缺失值、不规则的格式(通常出现在从网页上爬取的数据中,主要需要使用正则表达式处理,本文不做介绍)、数据噪声(如:传感器采集数据过程中产生的噪声)、异常值(如:收入:-15元,或身高:1688cm)。
数据预处理并不是一种算法模型,更像实战中用到的 trick。
数据预处理招无定法,不可以用同样的过程来对不同类型的数据集进行预处理,甚至对于类型相同,但数据采集过程有细微区别的两个数据集,使用完全相同的数据预处理流程,效果可能都会有极大的不同。
因此,这个 Chat 并非教授给你一种数据预处理的定式,而是把数据预处理的方法及思路分解,从而让你在自己进行数据处理的时候以这些方法为基础,将其拼接扩展,根据手中拿到的数据集的具体情况,来制定不同的数据预处理方法。
接下来,我将数据预处理的技巧分解成一个个小的点来展示,以便你在需要进行数据预处理的时候,可以浏览一遍,以便找到灵感。
数据预处理最基础的作用,就是去除数据中的噪声、异常值,纠正不一致。所以,数据预处理(data preprocessing)通常在狭义上也被称为数据清洗。
然而真正影响到模型效果的,并不只是这些,下面我将列举出在数据集中常见的对模型有影响的问题,并提出解决它们的方法与思路,并且还会列出其他对于模型好坏有极大影响的预处理方法。
一、特征间的量级差异
量级差距即特征间的范围不同,比如以下两个特征就会有量级的差距。
如果你是使用如决策树,可以无视此问题,因为数据间的量级差异对(决策)树模型(tree-based model)无影响。
因为 tree-based model 如 CART、GBDT 等,是根据每个特征的划分增益进行分枝决策,所以每次判断仅针对一个特征进行分割判断,所以可以无视特征间的量级差距,不会对模型的决策造成任何影响。
然而,数据的量级对除了树模型外的大多数模型都有很大的影响。
例如,某数据集包含 2 个特征 x1、x2,如果使用 kNN 算法,k 值为 1,对绿色个点进行预测,如下图所示。那么,与绿色的点最靠近的就是蓝色的 ×。
然而如果把 x1 的量级扩大 10 的六次方倍呢?如下图,与绿色点最接近的居然变成了红色的圆圈!所以,数据间量级的变换,将导致模型结果的大大不同!
同理,对于线性模型(如 SVM/ 感知机等等),如下图,如果按照原数据 (左图) 进行判断,SVM 的分割决策线应该是平行于 x1 轴,然而如果将 x1 轴的数据放大,分割决策线会与 x 轴则会成 45 度角。
解决方法:数据标准化
数据标准化(data normalization)就是将不同的特征按比例缩放,使之落入一个特定的区间。其中最典型的就是数据的归一化处理,即将数据统一映射到 [0,1] 区间上。
而且归一化除了让数据的量级变得相同外,还有另一个好处,就是当使用如神经网络等算法时,归一化的数据通常能够更快的收敛。
数据标准化方法有多种,不同的标准化方法,对数据集的影响都不同,在数据标准化方法的选择上,还没有通用的法则可以遵循。下面,为常见的数据标准化方法:
1. 极大极小规范化(MinMaxScaler)
(压缩至 [0,1]),每个数据都减去最小的值,再除以极差。
2. 方差规范化(StandardScaler)
压缩至约 [-1, 1],每个数据减去均值,再除以标准差。
理论上,要将所有的特征都进行标准化,否则特征见量级不同,对模型的影响会有差距。当然,也可以根据经验,适当增加或者减少 某些特征的量级。
二、异常值(outlier)
异常值,通常也可以理解为噪声,几乎对于所有的模型,异常值都会有影响。如下图,加入了一个异常值后,可能整个模型都会被改变。
异常值的常用检测方法:极差、中间四分位数极差、标准差。
首先,将数据根据某一特征的值的大小进行排序。
然后可计算下列几个数值:
极差:数据集的最大值和最小值的差;
百分位数:第 n 个百分位数是指 n% 的数据项位于或低于 x;
四分位数:第一个四分位数 Q1(第 25 个百分位数),第三个四分位数 Q3,中间四分位数极差(IQR)即 Q3 - Q1。
如果极差远大于 IQR,则说明存在很可能存在异常值,那么可以对异常值进行处理。
标准差同理,如果标准差过大,也可判断出存在异常值。
异常值的解决方法:
1. 百分位法
只留数值百分位数为 1 至 99 间的数据,这样就会避免异常值,比如在 Python 中的 numpy 可以轻易实现这个功能:
importnumpyasnpimportpandasaspdUPPERBOUND, LOWERBOUND = np.percentile(x, [1,99])y = np.clip(x, UPPERBOUND, LOWERBOUND)pd.Series(y).hist(bins=30)
2. 改变范围
将特征的数值变换到另外的空间中,这种方式可以让极大的异常值缩小,使他们对模型的影响变小,通常可用的空间变换函数为:
(1)Log 变换:
x = np.log(1+x)
(2)取小于 1 的方根:
x = np.sqrt(x+2/3)
三、缺失值
缺失值是经常存在的,产生的原因不多解释,缺失值的影响更不必多解释,下面来说解决办法。
1. 平均值 / 中位数 / 众数代替法
这三种就不多说了,都是很基础很简单的方法。
2. 插值法
常见的包括牛顿插值、拉格朗日插值等等,由于公式太多,本 chat 篇幅有限,就不具体讲解了,网上有很多具体实现的代码。
3. 聚类法
使用如 k-mean/kNN 等聚类方法,对存在缺失数据的点的特征值进行预测。
四、分类特征问题
考虑以下这个分类特征:
[“China”,”Japan”, “America”, “German”]
如果使用大多数机器学习算法,需要将该特征用数字表示,而不能直接使用字符串,因为至少计算会更高效,所以可以将其特征转换为
[0, 1, 2, 3]
然而,转化为数字表示后,直接用在模型中是不合适的。因为,模型会认为数据是有序的,也就是 “China”
为了解决上述问题,其中一种可能的解决方法是采用独热编码(One-Hot Encoding)。
One-Hot 编码,又称一位有效编码,其方法是使用 N 位状态寄存器来对 N 个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。
例如:
自然状态码为:0,1,2,3,4,5
独热编码为:000001,000010,000100,001000,010000,100000
可以这样理解,对于每个特征,如果它有 m 个可能值,那么经过独热编码后,就变成了 m 个二元特征。并且,这些特征互斥,每次只有一个激活。因此,数据会变成稀疏的。
领取专属 10元无门槛券
私享最新 技术干货