机器学习的特征缩放

数据输入机器学习模型前,需要先进行归一化或标准化,以便统一不同特征的量纲,加快学习速度

什么是特征缩放 (Featrue Scaling)?

  • 当一组输入特征的尺度相差很大,并且模型对于特征的尺度很敏感,就需要进行特征缩放 (特征正规化),从而消除数据特征之间量纲的影响,使得不同的特征之间具有可比性
  • 特征缩放总是将特征除以一个常数 (正规化常数),因此不会改变单特征的分布,只有数据尺度发生了变化。对数值型特征的特征做归一化可以将所有特征都统一到一个大致相同的数值区间内
  • 标准化 /z 值归一化 (Standardization/Z-Score Normalization) 和归一化 (Normalization) 都可以实现特征缩放,但两者是有区别的

为什么要进行特征缩放?

  • 量纲不同: 评价事物时,常常使用多指标进行综合评价,但是不同评价指标具有不同的量纲,直接使用原始指标值评价时,往往会削弱数值较小的指标的作用
  • 如果不进行特征缩放,加速现有特征x0=100,x1=1x_0=100,x_1=1 , 公式y=w0x0+w1x1+by=w_0*x_0+w_1*x_1+b 在计算损失函数时,w0w_0 相比较w0w_0 对 y 影响更大,梯度也更大,因此两个特征就不能使用相同的学习率

那些算法需要进行特征缩放?

  • 如果模型是输入特征的平滑函数,那么模型对输入的的尺度是非常敏感的
  • 通过梯度下降法求解的模型通常需要进行特征正规化,比如线性回归、逻辑回归、神经网络等
  • 使用欧式距离的方法,通常需要对特征进行标准化,以便将输出控制在期望的范围内,比如 K 近邻、K-Means、SVM、PCA 等
  • 基于树的算法(比如决策树)对特征(features)的数值范围并不敏感,不需要进行特征缩放
  • 线性判别分析(LinearDiscriminantAnalysis,LDA)、朴素贝叶斯等算法,处理了特征数量级差异大的问题,因此不需要进行特征缩放
  • 概率模型不需要归一化,因为它们不关心变量的值,而是关心变量的分布和变量之间的条件概率,如决策树、RF。而像 Adaboost、GBDT、XGBoost、SVM、LR、KNN、KMeans 之类的最优化问题就需要归一化

什么是最大绝对值归一化 (Max Abs Normalization)?

  • 将数值变为数值范围缩放到 [-1, 1] 区间里
  • x=xmax(x)x^{\prime}=\frac{x}{\|\max (x)\|}

什么是归一化 / 最大最小值归一化 (Min-Max Normalization) ?

  • 最大最小值归一化简称为归一化 (Normalization),将数值范围缩放到 [0,1] 区间里
  • x=xmin(x)max(x)min(x)x^{\prime}=\frac{x-\min (x)}{\max (x)-\min (x)}

什么是均值归一化 (Mean Normalization) ?

  • 将数值范围缩放到 [−1,1] 区间里,数据的均值变为 0
  • x=xmean(x)max(x)min(x)x^{\prime}=\frac{x-\operatorname{mean}(x)}{\max (x)-\min (x)}

什么是标准化 /z 值归一化 (Standardization/Z-Score Normalization) ?

  • 标准化也称为:方差缩放、零均值归一化、Z-Score Normalization,将数值缩放到 0 附近,且数据的分布变为均值为 0,标准差为 1 的标准正态分布
  • x=xmean(x)σ(x)x^{\prime}=\frac{x-\operatorname{mean}(x)}{\sigma(x)}

什么是稳键标准化 (Robust Standardization)?

  • 有些时候,数据中会存在离群点(异常值)。这时如果我们使用标准化 /z 值归一化 (Standardization/Z-Score Normalization) 就会导致数据很容易失去离群特征。这时我们就可以使用 RobustScaler 方法,它对于数据中心化和数据的缩放健壮性有着更强的参数调节能力
  • x=xmedian(x)IQRx^{\prime}=\frac{x-\operatorname{median}(x)}{IQR}

  • 公式先减去中位数,再除以四分位间距, 因为不涉及极值,因此在数据里有异常值的情况下表现比较稳健
    1
    2
    3
    4
    5
    import numpy as np
    ages=[3,3,6,7,7,10,10,10,11,13,30]
    lower_q=np.quantile(ages,0.25,interpolation='lower')#下四分位数
    higher_q=np.quantile(ages,0.75,interpolation='higher')#上四分位数
    int_r=higher_q-lower_q#四分位距

什么时候使用归一化 / 标准化?

  • 归一化和标准化的而区别在于,归一化是统一到一定的区间(由极值决定),而标准化和整体样本由很大关系
  • 如果对输出结果范围要求,用归一化
  • 如果数据较为稳定,不存在极端的最大最小值,用归一化
  • 如果存在噪音和异常值,可以使用标准化处理

特征缩放、标准化、归一化的关系?

  • 数据标准化、归一化都可以实现特征缩放
  • 归一化 (Normalization) 缩放:仅仅跟最大、最小值的差别有关,将样本的特征值转换到同一量纲下,把数据映射到 [0,1] 或者 [-1, 1] 区间内
  • 标准化 /z 值归一化 (Standardization/Z-Score Normalization) 缩放:和每个点都有关系,通过方差(variance)体现出来。与归一化对比,标准化中所有数据点都有贡献(通过均值和标准差造成影响)

机器学习中,为何要经常对数据做归一化?

  • 归一化后加快了梯度下降求最优解的速度
  • 归一化有可能提高精度

归一化的本质?优缺点?

  • 将各个维度上的数量级进行统一,把各个特征维度 X1…Xn 的数量级统一,做到无量纲化。归一化就是把数据归到 0 到 1 之间。
  • 归一化的方法:每一列的某个数据 - 每一列的最小值 / 每一列的最大值 - 每一列的最小值 ,列和列之间没有关系。
  • 优点:把数据都归到 0 到 1 之间,方便计算
  • 缺点:如果有一个离群值(异常值),对整列数据的影响是比较大的

什么是数据去中心化?

  • 去中心化:每组数据减去其平均值,使得数据的均值变为 0

什么是数据离散化?

  • 把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率
  • 例如,您可以将温度区间分割为离散分箱,而不是将温度表示成单个连续的浮点特征。假设温度数据可精确到小数点后一位,则可以将介于 0.0 到 15.0 度之间的所有温度都归入一个分箱,将介于 15.1 到 30.0 度之间的所有温度归入第二个分箱,并将介于 30.1 到 50.0 度之间的所有温度归入第三个分箱。

为什么要进行数据离散化?

  • 模型需要:比如决策树 (ID3,ID4.5,C4.5)、朴素贝叶斯(NBC)等算法,都是基于离散型的数据展开的。如果要使用该类算法,必须将离散型的数据进行。有效的离散化能减小算法的时间和空间开销,提高系统对样本的分类聚类能力和抗噪声能力
  • 快速迭代 :离散特征的增加和减少都很容易,易于模型的快速迭代
  • 特征交叉:离散化后可以进行特征交叉,相当于引入非线性,提升模型的表达能力

什么是数据因子化? ^y2mgu

  • 对于类别型特征,例如特征性别:{男人,女人},数据读取不容易,把它进行数值化

sklearn 中,如何进行数据的标准化 (StandardScaler)?

  • 使用 StandardScaler 即可
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     >>> from sklearn import preprocessing
    >>> import numpy as np
    >>> X_train = np.array([[ 1., -1., 2.],
    ... [ 2., 0., 0.],
    ... [ 0., 1., -1.]])
    >>> scaler = preprocessing.StandardScaler().fit(X_train)
    >>> scaler
    StandardScaler()
    >>> scaler.mean_
    array([1. ..., 0. ..., 0.33...])
    >>> scaler.scale_
    array([0.81..., 0.81..., 1.24...])
    >>> X_scaled = scaler.transform(X_train)
    >>> X_scaled
    array([[ 0. ..., -1.22..., 1.33...],
    [ 1.22..., 0. ..., -0.26...],
    [-1.22..., 1.22..., -1.06...]])

sklearn 中,如何进行数据的最大最小归一化 (MinMaxScaler)?

  • 将特征缩放到给定的最小值和最大值之间,通常在零和一之间,或者将每个特征的最大绝对值缩放到单位大小。这可以分别使用 MinMaxScaler 或来实现 MaxAbsScaler
  • 使用这种缩放的动机包括对非常小的特征标准偏差的鲁棒性以及在稀疏数据中保留零条目
    1
    2
    3
    4
    5
    6
    7
    8
    9
     >>> X_train = np.array([[ 1., -1.,  2.],
    ... [ 2., 0., 0.],
    ... [ 0., 1., -1.]])
    >>> min_max_scaler = preprocessing.MinMaxScaler()
    >>> X_train_minmax = min_max_scaler.fit_transform(X_train)
    >>> X_train_minmax
    array([[0.5 , 0. , 1. ],
    [1. , 0.5 , 0.33333333],
    [0. , 1. , 0. ]])

sklearn 中,如何进行稀疏数据的标准化 (MaxAbsScaler)?

  • MaxAbsScaler 个估计器对每个特征进行单独的缩放和翻译,使训练集中每个特征的最大绝对值为 1.0。它不对数据进行转移 / 居中,因此不会破坏任何稀疏性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     >>> from sklearn.preprocessing import MaxAbsScaler
    >>> X = [[ 1., -1., 2.],
    ... [ 2., 0., 0.],
    ... [ 0., 1., -1.]]
    >>> transformer = MaxAbsScaler().fit(X)
    >>> transformer
    MaxAbsScaler()
    >>> transformer.transform(X)
    array([[ 0.5, -1. , 1. ],
    [ 1. , 0. , 0. ],
    [ 0. , 1. , -0.5]])

sklearn 中,如何进行异常值的标准化 (RobustScaler)?

  • 数据集的标准化是许多机器学习估计器的一个共同要求。通常情况下,这是由去除平均值和缩放到单位方差来完成的。然而,异常值往往会以负面的方式影响样本的平均值 / 方差。在这种情况下,中位数和四分位数范围往往能提供更好的结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     >>> from sklearn.preprocessing import RobustScaler
    >>> X = [[ 1., -2., 2.],
    ... [ -2., 1., 3.],
    ... [ 4., 1., -2.]]
    >>> transformer = RobustScaler().fit(X)
    >>> transformer
    RobustScaler()
    >>> transformer.transform(X)
    array([[ 0. , -2. , 0. ],
    [-1. , 0. , 0.4],
    [ 1. , 0. , -1.6]])

sklearn 中,如何进行数据的非线性变换?

  • 有两种类型的变换可用:分位数变换和幂变换。分位数和幂变换都基于特征的单调变换,因此保留了沿每个特征的值的等级; 幂变换是一系列参数变换,旨在将数据从任何分布映射到尽可能接近高斯分布
  • QuantileTransformer 提供一个非参数变换,将数据映射到值在 0 和 1 之间的均匀分布
    1
    2
    3
    4
    5
    6
    7
    8
    9
     >>> from sklearn.datasets import load_iris
    >>> from sklearn.model_selection import train_test_split
    >>> X, y = load_iris(return_X_y=True)
    >>> 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)
    >>> np.percentile(X_train[:, 0], [0, 25, 50, 75, 100])
    array([ 4.3, 5.1, 5.8, 6.5, 7.9])
  • 在许多建模场景中,数据集中特征的正态性是可取的。幂变换是一系列参数单调变换,旨在将数据从任何分布映射到尽可能接近高斯分布,以稳定方差并最小化偏度
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     >>> pt = preprocessing.PowerTransformer(method='box-cox', standardize=False)
    >>> X_lognormal = np.random.RandomState(616).lognormal(size=(3, 3))
    >>> X_lognormal
    array([[1.28..., 1.18..., 0.84...],
    [0.94..., 1.60..., 0.38...],
    [1.35..., 0.21..., 1.09...]])
    >>> pt.fit_transform(X_lognormal)
    array([[ 0.49..., 0.17..., -0.15...],
    [-0.05..., 0.58..., -0.57...],
    [ 0.69..., -0.84..., 0.10...]])

sklearn 中,如何进行数据的归一化 (normalize)?

  • 归一化是将单个样本按比例调整为具有单位规范的过程
    1
    2
    3
    4
    5
    6
    7
    8
     >>> X = [[ 1., -1.,  2.],
    ... [ 2., 0., 0.],
    ... [ 0., 1., -1.]]
    >>> X_normalized = preprocessing.normalize(X, norm='l2')
    >>> X_normalized
    array([[ 0.40..., -0.40..., 0.81...],
    [ 1. ..., 0. ..., 0. ...],
    [ 0. ..., 0.70..., -0.70...]])

sklearn 中,如何编码分类特征?

  • 通常特征不是作为连续值而是分类的。例如,一个人可能有特征,, 。这些特征可以有效地编码为整数
  • 要将分类特征转换为此类整数代码,我们可以使用 OrdinalEncoder. 该估计器将每个分类特征转换为一个新的整数特征(0 到 n_categories - 1)
    1
    2
    3
    4
    5
    6
     >>> enc = preprocessing.OrdinalEncoder()
    >>> X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
    >>> enc.fit(X)
    OrdinalEncoder()
    >>> enc.transform([['female', 'from US', 'uses Safari']])
    array([[0., 1., 1.]])

sklearn 中,如何进行数据的离散化?

  • 离散化 (也称为量化或分箱)提供了一种将连续特征划分为离散值的方法。某些具有连续特征的数据集可能会受益于离散化,因为离散化可以将连续属性的数据集转换为仅具有名义属性的数据集
  • One-hot 编码的离散化特征可以使模型更具表现力,同时保持可解释性。例如,使用离散化器进行预处理可以将非线性引入线性模型。有关更高级的可能性,尤其是平滑的可能性
  • K-bins 离散化: 默认情况下,输出被单热编码为稀疏矩阵
    1
    2
    3
    4
    5
    6
    7
    8
     >>> X = np.array([[ -3., 5., 15 ],
    ... [ 0., 6., 14 ],
    ... [ 6., 3., 11 ]])
    >>> est = preprocessing.KBinsDiscretizer(n_bins=[3, 2, 2], encode='ordinal').fit(X)
    >>> est.transform(X)
    array([[ 0., 1., 1.],
    [ 1., 1., 1.],
    [ 2., 0., 0.]])
  • 特征二值化: 对数值特征进行阈值处理以获得布尔值
    1
    2
    3
    4
    5
    6
    7
    8
     >>> X = [[ 1., -1.,  2.],
    ... [ 2., 0., 0.],
    ... [ 0., 1., -1.]]
    >>> binarizer = preprocessing.Binarizer(threshold=1.1)
    >>> binarizer.transform(X)
    array([[0., 0., 1.],
    [1., 0., 0.],
    [0., 0., 0.]])

sklearn 中,如何生成多项式特征?

  • 通过考虑输入数据的非线性特征来增加模型的复杂性是有用的
  • 基于纯多项式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     >>> import numpy as np
    >>> from sklearn.preprocessing import PolynomialFeatures
    >>> X = np.arange(6).reshape(3, 2)
    >>> X
    array([[0, 1],
    [2, 3],
    [4, 5]])
    >>> poly = PolynomialFeatures(2)
    >>> poly.fit_transform(X)
    array([[ 1., 0., 1., 0., 0., 1.],
    [ 1., 2., 3., 4., 6., 9.],
    [ 1., 4., 5., 16., 20., 25.]])
  • 基于分段多项式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     >>> import numpy as np
    >>> from sklearn.preprocessing import SplineTransformer
    >>> X = np.arange(5).reshape(5, 1)
    >>> X
    array([[0],
    [1],
    [2],
    [3],
    [4]])
    >>> spline = SplineTransformer(degree=2, n_knots=3)
    >>> spline.fit_transform(X)
    array([[0.5 , 0.5 , 0. , 0. ],
    [0.125, 0.75 , 0.125, 0. ],
    [0. , 0.5 , 0.5 , 0. ],
    [0. , 0.125, 0.75 , 0.125],
    [0. , 0. , 0.5 , 0.5 ]])