推荐书: Python开发最佳实践

机器学习数据预处理技术(标准化-缩放-正则化)

分享时@该用户已经被封, 我就能回答你的问题奥!

文章目录
  1. 1. 简介
  2. 2. 数据预处理技术介绍
  3. 3. 数据标准化
    1. 3.0.1. sklearn.preprocessing.scale
    2. 3.0.2. sklearn.preprocessing.StandardScaler
  • 4. 数据缩放
    1. 4.0.1. MinMaxScaler or MaxAbsScaler
  • 4.1. 缩放稀疏数据
  • 4.2. 带有异常值的数据缩放
  • 4.3. 缩放和白化(whitening)
  • 5. 非线性转换¶
  • 6. 正则化
  • 7. 未完待续

  • 简介

    机器学习模型千变万化, 每种模型需要的数据形式都略有不同, 所以我们一般花在数据提取/清理/格式化等操作的时间可能会占项目总时间的百分之七十(甚至更多)。

    不过, 借助别人已经写好的程序可以让我们的工作事半功倍。今天我们介绍的一个工具就是著名的python机器学习库sklearn, 它包含很多数据预处理技术, 下面我们就来列出常用的一些数据预处理技术, 以便大家提高效率, 也是给我自己的一个技术笔记。

    数据预处理技术介绍

    数据集的标准化是scikit-learn中实现的许多机器学习估计器的通用要求;如果单个特征看起来不像标准正态分布数据那么它们可能会表现得很差:高斯分布的零均值和单位方差。

    在实践中,我们经常忽略分布的形状,只是通过去除每个特征的平均值来将数据转化为中心,然后通过将特征向量除以它们的标准差来对其进行调整。

    例如,学习算法的目标函数(如支持向量机的RBF核或线性模型的l1和l2正则化)中使用的许多元素都假定所有特征都以零为中心并具有相同数量级的方差。如果一个特征的方差比其他特征要大几个数量级,那么它可能会影响目标函数,使得算法无法正确地按照预期正确地学习其他特征。

    数据标准化

    sklearn.preprocessing.scale

    函数scale提供了一种在单个类似数组的数据集上执行标准化操作的快捷方法:

    (也就是特征向量减去平均值除以标准差)

    1
    2
    from sklearn import preprocessing
    import numpy as np
    1
    2
    3
    np.random.seed(1)
    X = np.random.rand(3,3)
    X
    输出: array([[4.17022005e-01, 7.20324493e-01, 1.14374817e-04], [3.02332573e-01, 1.46755891e-01, 9.23385948e-02], [1.86260211e-01, 3.45560727e-01, 3.96767474e-01]])
    1
    2
    3
    4
    # 在垂直方向上做标准化
    X_scaled = preprocessing.scale(X)
    mean = X_scaled.mean(axis=0)
    print('Mean:', mean)
    输出: Mean: [ 1.48029737e-16 -1.11022302e-16 7.40148683e-17]
    1
    2
    std = X_scaled.std(axis=0)
    print('Std:', std)
    输出: Std: [1. 1. 1.]
    sklearn.preprocessing.StandardScaler

    我们经常需要保存训练阶段使用的标准差和平均值, sklearn为我们做好了一切。

    预处理模块还提供了一个实用程序类StandardScaler,它实现了Transformer API来计算训练集上的平均值和标准差,以便稍后能够在测试集上重新应用相同的转换。因此该类适用于sklearn.pipeline.Pipeline的早期步骤:

    1
    2
    scaler = preprocessing.StandardScaler().fit(X)
    print('Mean:', scaler.mean_)
    输出: array([0.3018716 , 0.4042137 , 0.16307348])
    1
    print('Std:', scaler.scale_)

    在测试阶段, 我们只需要使用StandardScaler进行数据转换即可:

    1
    2
    X_test = np.random.rand(3,3)
    scaler.transform(X_test)
    输出: array([[-1.71411671, -0.86673532, 3.76248109], [ 7.07355245, -0.38178469, 3.12275387], [ 6.0983511 , 2.06218199, -0.46039982]])

    数据缩放

    MinMaxScaler or MaxAbsScaler

    (将特征向量缩放至一定范围)

    另一种标准化是缩放功能位于给定的最小值和最大值之间,通常在0和1之间,或者使每个功能的最大绝对值按比例缩放到单位大小。这可以分别使用MinMaxScalerMaxAbsScaler来实现。

    使用这种扩展的目的包括对特征的非常小的标准偏差的鲁棒性以及在稀疏数据中保留零条目。

    • MinMaxScaler 的转换类似于以下代码:
    1
    2
    3
    4
    ### 标准化
    X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
    ### 复原
    X_scaled = X_std * (max - min) + min
    • MaxAbsScaler 的转换类似于以下代码:
    1
    2
    3
    4
    ### 标准化
    X_std = X / X.max(axis=0)
    ### 复原
    X_scaled = X_std * max

    MaxAbsScaler以非常相似的方式工作,但通过除以每个特征中的最大值来使数据在[-1,1]范围内。这意味着你需要自己对数据中心化负责(它没有做中心化)。

    以下是将数据矩阵缩放到[0,1]范围的示例, 使用了MinMaxScaler类:

    1
    2
    X = np.random.rand(3,3)*3
    X
    输出: array([[2.05950278, 2.50387702, 0.05486483], [2.25043294, 2.96658327, 2.24449696], [0.84133198, 2.36783799, 0.30967802]])
    1
    2
    3
    scaler = preprocessing.MinMaxScaler()
    X_transformed = scaler.fit_transform(X)
    X_transformed
    输出: array([[0.86450214, 0.22720685, 0. ], [1. , 1. , 1. ], [0. , 0. , 0.1163726 ]])
    1
    print('range:', scaler.data_range_)
    输出: range: [1.40910097 0.59874528 2.18963213]
    1
    print('Min:', scaler.data_min_, 'Max:', scaler.data_max_)
    输出: Min: [0.84133198 2.36783799 0.05486483] Max: [2.25043294 2.96658327 2.24449696]

    缩放稀疏数据

    将稀疏数据中心化会破坏数据中的稀疏结构,因此很少是明智的做法。然而,缩放稀疏数据是有意义的,特别是如果特征向量在不同的尺度上。

    MaxAbsScalermaxabs_scale专门用于缩放稀疏数据,并且是推荐的方法。但是,scaleStandardScaler可以接受scipy.sparse矩阵作为输入,只要将with_mean = False显式传递给构造函数即可。否则就会产生ValueError,因为静默集中会破坏稀疏性,并且通常会无意中分配过多的内存而导致执行崩溃。 RobustScaler无法适应稀疏输入,但可以在稀疏输入上使用变换方法。

    请注意,scalers接受压缩稀疏行和压缩稀疏列格式(请参阅scipy.sparse.csr_matrixscipy.sparse.csc_matrix)。任何其他稀疏输入将被转换为压缩稀疏行表示。为避免不必要的内存拷贝,建议在上游选择CSR或CSC表示。

    最后,如果预期中心化后的数据足够小,则使用稀疏矩阵的方法显式地将输入转换为矩阵是另一种选择。

    带有异常值的数据缩放

    如果您的数据包含很多异常值,则使用数据的平均值和方差进行缩放可能无法很好地工作。在这些情况下,您可以使用robust_scaleRobustScaler作为替换。他们对数据的中心和范围使用更稳健的估计。

    缩放和白化(whitening)

    由于下游模型可以进一步对特征的线性独立性作出一些假设,所以只做标准化是不够的。所以才有白化(whitening)的技术要求。它就是将特征向量之间的相关性消除。

    要解决此问题,您可以使用sklearn.decomposition.PCAsklearn.decomposition.RandomizedPCA 设置 whiten = True来进一步删除跨特征的线性相关性。关心这个技术的请参考我的博客。

    非线性转换¶

    与缩放器一样,QuantileTransformer将每个特性放入相同的范围或分布。然而,通过执行等级转换,它可以消除不寻常的分布,并且比缩放方法更少受异常值的影响。但是,它会扭曲特征内和特征间的相关性和距离。

    QuantileTransformerquantile_transform提供基于分位数函数的非参数变换,以便将数据映射到0到1之间的均匀分布。他的方法将功能转换为均匀或正态分布。因此,对于一个给定的特征,这种转换倾向于分散高频值。它也减少了(边际)异常值的影响:因此这是一个强大的预处理方案。

    该转换是独立应用于每个功能的。特征的累积密度函数用于投影原始值。低于或高于拟合范围的新/未见数据的特征值将被映射到输出分布的边界。请注意,这种转换是非线性的。它可能会扭曲在相同规模下测量的变量之间的线性相关性,但会使得在不同规模下测量的变量更加直接可比。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from sklearn.datasets import load_iris
    from sklearn.model_selection import train_test_split
    iris = load_iris()
    X, y = iris.data, iris.target
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
    quantile_transformer = preprocessing.QuantileTransformer(random_state=0)
    X_train_trans = quantile_transformer.fit_transform(X_train)
    X_test_trans = quantile_transformer.transform(X_test)
    rtn = np.percentile(X_train[:, 0], [0, 25, 50, 75, 100])
    print('原始数据的分位数:', rtn)
    输出: 原始数据的分位数: [4.3 5.1 5.8 6.5 7.9]
    1
    2
    rtn2 = np.percentile(X_train_trans[:, 0], [0, 25, 50, 75, 100])
    print('转换后的分位数:', rtn2)
    输出: 转换后的分位数: [9.99999998e-08 2.38738739e-01 5.09009009e-01 7.43243243e-01 9.99999900e-01]

    测试集上也会进行相似的转换, 可以看到:

    1
    np.percentile(X_test[:, 0], [0, 25, 50, 75, 100])
    输出: array([4.4 , 5.125, 5.75 , 6.175, 7.3 ])

    正则化

    正态化是将单个样本缩放为单位规范的过程。如果你计划使用诸如点积或任何其他内核的二次形式来量化任何一对样本的相似性,则此过程可能很有用。

    这个假设是经常用于文本分类和聚类上下文的矢量空间模型的基础。

    函数normalize提供了一种快速简便的方法,可以使用l1或l2范数在单个类似数组的数据集上执行此操作。

    Normalization主要思想是对每个样本计算其p-范数,然后对该样本中每个元素除以该范数,这样处理的结果是使得每个处理后样本的p-范数(l1-norm,l2-norm)等于1。

    p-范数的计算公式:||X||p=(|x1|^p+|x2|^p+…+|xn|^p)^1/p

    最常见的2范数可以表述为: 向量的每个元素的平方和再开方。

    1
    2
    3
    X = np.random.rand(3,3)
    X_normalized = preprocessing.normalize(X, norm='l2')
    X_normalized
    输出: array([[0.42466981, 0.86148394, 0.27838997], [0.90958378, 0.41098685, 0.06121397], [0.89435184, 0.27881569, 0.34985226]])

    预处理模块还提供了一个工具类Normalizer,它使用Transformer API实现相同的操作(即使在这种情况下fit方法是无用的:因为此操作独立处理样本,所以类是无状态的)。

    因此该类适用于sklearn.pipeline.Pipeline的早期步骤:

    1
    2
    normalizer = preprocessing.Normalizer()
    normalizer.transform(X)
    输出: array([[0.42466981, 0.86148394, 0.27838997], [0.90958378, 0.41098685, 0.06121397], [0.89435184, 0.27881569, 0.34985226]])

    未完待续

    这篇文章还有一个续篇, 大家可以看看: 机器学习数据预处理技术(二值化-连续化-估计缺失值-多项式)

    注意
    本文由jupyter notebook转换而来, 您可以在这里下载notebook.ipynb)
    有问题可以直接在下方留言
    或者给我发邮件675495787[at]qq.com
    请记住我的网址: mlln.cn 或者 jupyter.cn