数据预处理入门

以 sklearn 中的鸢尾花数据集为例来对数据预处理进行说明。鸢尾花数据集内包含 3 类共 150 条记录,每类各 50 个数据,每条记录都有 4 项特征:花萼长度(sepal length)、花萼宽度(sepal width)、花瓣长度(petal length)、花瓣宽度(petal length)。

导入鸢尾花数据集的代码如下:

from sklearn.datasets import load_iris
 
#导入IRIS数据集
iris = load_iris()

1 无量纲化

如果特征的规格不一样,就不能够放在一起比较。

比如:在两个样本中肿瘤大小的分别为 1 cm 和 5 cm,发现时间分别为 100 天和 200 天,那么在求距离时,时间差为 100,大小差为 4,那么其结果会被时间所主导,因为肿瘤大小的差距太小了。但是如果我们把时间用年做单位,0.27 年与 0.55 年的差距又远小于肿瘤大小的差距,结果又会被大小主导了。

这时就需要无量纲化处理,无量纲化使不同规格的数据转换到同一规格。常见的无量纲化方法有归一化和标准化。

1.1 归一化

常用的数据归一化方法有:

  • Min-Max Normalization,将数据归一化到 [0, 1] 之间,公式为:

    x s c a l e = x x m i n x m a x x m i n x_{scale}=\frac{x-x_{min}}{x_{max}-x_{min}}

    使用 sklearn.preproccessing 库的 MinMaxScaler 类对数据进行归一化处理,默认归一到 [0, 1] 之间,的代码如下:

    from sklearn.preprocessing import MinMaxScaler
    
    #区间缩放,返回值为缩放到[0, 1]区间的数据
    MinMaxScaler().fit_transform(iris.data)
    

    使用 MinMaxScaler 的参数 feature_range 实现将数据归一到 [0, 1] 以外的范围:

    data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
    MinMaxScaler(feature_range=[5, 10]).fit_trainsform(data)         # 归一到[5, 10]之间
    
  • 平均归一化,将数据归一化到 [-1, 1] 之间,公式为:

x s c a l e = x x ˉ x m a x x m i n x_{scale}=\frac{x-\bar{x}}{x_{max}-x_{min}}

其中,$ \bar{x} 为均值, \bar{x}=\frac{\sum_{i=1}^{n}x_i}{n}$

  • 非线性归一化:

    经常用在数据分化比较大的场景,有些数值很大,有些很小。通过一些数学函数,将原始值进行映射。

    该方法包括 log、指数,正切等。需要根据数据分布的情况,决定非线性函数的曲线,比如 log(V, 2) 还是 log(V, 10) 等。

1.2 标准化

标准化的前提是特征值服从正态分布,标准化后,其转换成标准正态分布。

Z-score 标准化(Z-score standardization,0-均值标准化),使数据均值为 0, 方差为 1,公式为:

x s c a l e = x x ˉ s x_{scale}=\frac{x-\bar{x}}{s}

其中, x ˉ \bar{x} 为均值, x ˉ = i = 1 n x i n \bar{x}=\frac{\sum_{i=1}^{n}x_i}{n}

s 为标准差, s = i = 1 n ( x i x ˉ ) 2 n s=\sqrt{\frac{\sum_{i=1}^{n}\left(x_{i}-\bar{x}\right)^{2}}{n}}

使用 sklearn.preproccessing 库的 StandardScaler 类对数据进行标准化的代码如下:

from sklearn.preprocessing import StandardScaler
 
#标准化,返回值为标准化后的数据
StandardScaler().fit_transform(iris.data)

1.3 归一化与标准化的比较

  • 相同点:

    归一化和标准化的目的都是取消由于量纲不同引起的误差;

    两者都是一种线性变换,都是把数据按照比例压缩再进行平移。

  • 不同点:

    • 目的不同,归一化是为了将数据压缩到某一限定的区间,比如 [0, 1] 之间;

      标准化只是调整特征整体的分布;

    • 归一化与最大,最小值有关,对异常值敏感;

      标准化与均值,标准差有关;

    • 归一化输出限定在一定的范围内;

      标准化要求数据的特征值符合正态分布;

  • 应用场景:

    • 在分类、聚类算法中,需要使用距离来度量相似性的时候(如 SVM、KNN)、或者使用 PCA 技术进行降维的时候,标准化(Z-score standardization)表现更好;

    • 在不涉及距离度量、协方差计算、数据不符合正态分布的时候,可以使用归一化方法。

      例如图像处理中,将 RGB 图像转换为灰度图像后将其值限定在 [0 255] 的范围;

    • 基于树的方法不需要进行特征的归一化。

      例如随机森林,bagging 与 boosting 等方法。

      如果是基于参数的模型或者基于距离的模型,因为需要对参数或者距离进行计算,都需要进行归一化。

总结来说,建议优先使用标准化。对于输出有要求时再尝试别的方法,如归一化或者更加复杂的方法。很多方法都可以将输出范围调整到 [0,
1],如果我们对于数据的分布有假设的话,更加有效的方法是使用相对应的概率密度函数来转换。

2 缺失值处理

数据中,常常会有重要的字段缺失值很多,但又不能舍弃字段的情况。因此,数据预处理中非常重要的一项就是处理缺失值。

由于鸢尾花数据集没有缺失值,故对数据集新增一个样本,4 个特征均赋值为 NaN,表示数据缺失。

使用 sklearn.preproccessing 库的 Imputer 类对数据进行缺失值计算的代码如下:

from numpy import vstack, array, nan
from sklearn.preprocessing import Imputer
# 缺失值计算,返回值为计算缺失值后的数据
# 参数missing_value为缺失值的表示形式,默认为NaN
# 参数strategy为缺失值填充方式,默认为mean(均值)
Imputer().fit_transform(vstack((array([nan, nan, nan, nan]), iris.data)))

3 处理分类型特征:编码与哑变量

在现实生活中,许多标签和特征在数据收集完毕的时候,都不是以数字来表现的,而是分类数据。比如说,学历的取值可以是 [“小学”,“初中”,“高中”,“大学”],付费方式可能包含 [“支付宝”,“现金”,“微信”] 等等。然而,大部分算法都只能够处理数值型数据,在这种情况下,为了让数据适应算法和库,我们必须将数据进行编码,即是说,将文字型数据转换为数值型

  • 使用 sklearn.preprocessing 库中的 LabelEncoder 类,标签专用,将分类标签转化为分类数值;

  • 使用 sklearn.preprocessing 库中的 OrdinalEncoder 类,标签专用,将分类特征转化为分类数值;

  • 使用 sklearn.preprocessing 库中的 OneHotEncoder 类,独热编码,创建哑变量;

    由于鸢尾花数据集的特征皆为定量特征,故使用其目标值进行哑编码(实际上是不需要的),代码如下:

    from sklearn.preprocessing import OneHotEncoder
    # 哑编码,对IRIS数据集的目标值,返回值为哑编码后的数据
    OneHotEncoder().fit_transform(iris.target.reshape((-1,1)))
    

为什么要使用哑变量呢?

我们考虑三种不同性质的分类数据:

  1. 付费方式(支付宝,现金,微信)

    三种取值是相互独立的,彼此之间完全没有联系,表达的是支付宝 ≠ 现金 ≠ 微信的概念。这是名义变量。

  2. 学历(小学,初中,高中)

    三种取值不是完全独立的,在性质上可以有高中 > 初中 > 小学这样的联系,学历有高低,但是学历取值之间却不是可以计算的,不能说小学 + 某个取值 = 初中。这是有序变量。

  3. 体重(>45kg,>90kg,>135kg)

    各个取值之间有联系,且是可以互相计算的,比如 120kg - 45kg = 90kg,分类之间可以通过数学计算互相转换。这是有距变量。

在对特征进行编码的时候,如果简单的就把分类数据转换成 [0, 1, 2],这三个数字在算法看来是连续,有大小且可以计算的,算法会把付费方式,学历这样的分类特征,都误会成是体重这样的分类特征。这是说,我们把分类转换成数字的时候,忽略了数字中自带的数学性质,所以给算法传达了一些不准确的信息,而这会影响我们的建模。

所以使用哑变量,也就是独热编码的方式,让算法能够彻底领悟,三个取值是没有可计算性质的(这里正好与自然语言处理中的 one-hot 编码相反,在 NLP 中我们摒弃了传统的 one-hot 编码,因为它无法表示出每个单词之间的相似性)。

4 处理连续型特征:二值化与分段

连续型特征二值化的核心在于设定一个阈值,大于阈值的赋值为1,小于等于阈值的赋值为0,公式如下:

x = { 1 , x >  threshold  0 , x  threshold  x^{\prime}=\left\{\begin{array}{l}{1, x>\text { threshold }} \\ {0, x \leq \text { threshold }}\end{array}\right.

使用 sklearn.preprocessing 库中的 Binarizer 类对数据进行二值化,代码如下:

from sklearn.preprocessing import Binarizer
# 二值化,阈值设置为3,返回值为二值化后的数据
Binarizer(threshold=3).fit_transform(iris.data)

参考资料:

本系列为参加自公众号「数据科学家联盟」的机器学习小组的系列笔记

【数据科学家学习小组】之机器学习(第一期)第三周:https://mp.weixin.qq.com/s/x00bAoFg2LUa2kihIZo_HA

特征工程系列:特征预处理(上):https://mp.weixin.qq.com/s/qWO9zgKyntvyWfftpGqrHQ

使用 sklearn 做单机特征工程:https://www.cnblogs.com/jasonfreak/p/5448385.html

sklearn 中的特征预处理和特征工程:https://www.cnblogs.com/juanjiang/archive/2019/05/30/10948849.html

发布了34 篇原创文章 · 获赞 9 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Shine_rise/article/details/103150167