美文网首页机器学习与计算机视觉机器学习与数据挖掘机器学习算法
[机智的机器在学习] 机器学习中的归一化和正则化问题

[机智的机器在学习] 机器学习中的归一化和正则化问题

作者: Alvin_2580 | 来源:发表于2018-03-18 15:43 被阅读17次

    今天我们要说的是,在机器学习常用的算法里面,那些需要归一化,那些不需要,通过scikit-learn中的预处理的一些方法,实际了解如何正则化和归一化数据。看完本文,应该对于一般的机器学习任务,都可以轻松上手操作。

    先看一下归一化是什么意思,对于一个机器学习任务来说,首先要有数据,数据怎么来?一种情况是别人整理好给你,一种是自己造数据,根据不同的业务场景,自己提取想要的数据,一般来自各个维度的数据,也就是常说的统计口径不一样,造成的结果是得到的数据大小范围变换非常大,并且可能数据类型也不一样,统计学里面把数据分为数值型数据、分类型数据、顺序型数据,对这些数据怎么处理成统一的口径的问题,就是机器学习中数据归一化问题。

    机器学习任务一般分为3种,也可以是两种,分类、回归和聚类,其中聚类也可以看做是分类。如果需要预测的值是离散型数据,就是分类任务,如果预测值是连续型数据,就是回归任务。常用的回归模型,也几乎都可以做分类,只需要把输出变为分类的类别数的概率值即可。常用的机器学习模型有广义线性模型,集成模型,线性判别分析、支持向量机、K近邻、朴素贝叶斯、决策树、感知机、神经网络等。其中广义线性模型包括线性回归、岭回归、Lasso回归、最小角回归、逻辑回归、贝叶斯回归、多项式回归、Elastic Net等。集成的方法包括随机森林、AdaBoost、梯度树提升等。

    机器学习中的模型这么多,怎么分的清那个需要归一化,那个不需要呢,这里有一个一般的准则,就是需要归一化的模型,说明该模型关心变量的值,而相对于概率模型来说,关心的是变量的分布和变量之间的条件概率。所以大部分概率模型不需要归一化。还有就是如果模型使用梯度下降法求最优解时,归一化往往非常有必要,否则很难收敛甚至不能收敛。

    然后说一下常用的归一化的方法,利用scikit-learn这个工具,把里面提到的归一化方法挨个过一遍。

    1. 均值,1标准差归一化,也叫z-score标准化

    顾名思义,就是把数据的均值变到0,方差变到1,公式为:


    image.png

    其中x是原始数据,z是变化后的数据,u是均值,sigma是方差。一般一个机器学习的数据集都是M*N的一个大的矩阵,M代表样本数,N代表特征的个数,其中的均值和方差,指的是整个大的矩阵的均值和方差,x是任意一个样本,xij,即:


    image.png
    下同,不在说明。

    然后用scikit-learn来实现z-score标准化的方法是下面这个:

    这里把需要的方法都import进来了,后面不再提示。

    import numpy as np
    from sklearn import preprocessing
    from sklearn.datasets import load_diabetes
    from sklearn.model_selection import train_test_split
    from sklearn.preprocessing import PolynomialFeatures
    
    from sklearn.preprocessing import FunctionTransformer
    
    diabetes = load_diabetes()
    X = diabetes.data
    y = diabetes.target
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
    
    print("X shape:{},y shape:{}".format(X_train.shape, y_train.shape))
    
    X_scaled = preprocessing.scale(X_train, axis=0, with_mean=True, with_std=True, copy=True)
    m = X_scaled.mean(axis=0)
    s = X_scaled.std(axis=0)
    print("Mean:{}, \n Std:{}".format(m, s))
    """
    X shape:(331, 10),y shape:(331,)
    Mean:[ -4.46101699e-17   2.42840323e-16   2.01248887e-18  -2.12988405e-17
      -2.34790368e-17  -2.49884034e-17  -1.25780554e-17  -5.16538809e-17
      -1.34165924e-17   1.67707406e-17], 
     Std:[ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
     """
    

    或者

    # 另一种方法
    scaler = preprocessing.StandardScaler(copy=True, with_mean=True, with_std=True).fit(X_train)
    X_scaled = scaler.transform(X_train)
    m = X_scaled.mean(axis=0)
    s = X_scaled.std(axis=0)
    print("Mean:{}, \n Std:{}".format(m, s))
    """
    Mean:[ -4.46101699e-17   2.42840323e-16   2.01248887e-18  -2.12988405e-17
      -2.34790368e-17  -2.49884034e-17  -1.25780554e-17  -5.16538809e-17
      -1.34165924e-17   1.67707406e-17], 
     Std:[ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
    """
    
    
    1. 最大-最小归一化

    就是把数据变到[0,1]区间内,公式为:


    image.png
    # 最大最小归一化,归一化到[0,1]之间
    min_max_scaler = preprocessing.MinMaxScaler()
    X_train_minmax = min_max_scaler.fit_transform(X_train)
    print()
    ma = X_train_minmax.max(axis=0)
    mi = X_train_minmax.min(axis=0)
    print("max:{},\n min:{}".format(ma, mi))
    """
    max:[ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.],
     min:[ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
     """
    

    还有一种是把数据归一到[-1,1]之间,公式为:


    image.png
    # 最大最小归一化,归一化到[-1,1]之间
    max_abs_scaler = preprocessing.MaxAbsScaler()
    x_maxabs = max_abs_scaler.fit_transform(X_train)
    
    ma = x_maxabs.max(axis=0)
    mi = x_maxabs.min(axis=0)
    print("max:{},\n min:{}".format(ma, mi))
    """
    max:[ 1.          1.          1.          1.          1.          1.          1.
      1.          1.          0.98435481],
     min:[-0.96838121 -0.88085106 -0.52930243 -0.85122699 -0.70749565 -0.58158979
     -0.5646737  -0.41242062 -0.94384991 -1.        ]
     """
    
    1. 正则化

    正则化方法包括l1,l2,max正则三种方法,在数学里也叫l1范数,l2范数,简单理解就是取绝对值和绝对值的平方在开方得到的结果。看代码

    
    X_normalized = preprocessing.normalize(X, norm='l2', axis=1, copy=True, return_norm=False)  
    # l2, l1, max
    
    print()
    print("{},\n {}".format(X[0], X_normalized[0]))
    """
    [ 0.03807591  0.05068012  0.06169621  0.02187235 -0.0442235  -0.03482076
     -0.04340085 -0.00259226  0.01990842 -0.01764613],
     [ 0.32100597  0.42726811  0.52014127  0.18439893 -0.37283438 -0.29356288
     -0.36589885 -0.02185454  0.16784162 -0.14876892]
     """
    # 另一种方法
    normalizer = preprocessing.Normalizer(norm='l2', copy=True).fit(X)
    X_normalized = normalizer.transform(X)
    print()
    print("{},\n {}".format(X[0], X_normalized[0]))
    """
    [ 0.03807591  0.05068012  0.06169621  0.02187235 -0.0442235  -0.03482076
     -0.04340085 -0.00259226  0.01990842 -0.01764613],
     [ 0.32100597  0.42726811  0.52014127  0.18439893 -0.37283438 -0.29356288
     -0.36589885 -0.02185454  0.16784162 -0.14876892]
     """
    

    4 变换数据的分布

    将原始数据变换成均匀分布,这样会改变原始数据的分布和变量间的相关性。其实这个和下面的多项式变换不属于归一化处理,只是一种数据变换的方式。

    quantile_transformer = preprocessing.QuantileTransformer(random_state=0)
    X_train_trans = quantile_transformer.fit_transform(X_train)
    percentile = np.percentile(a=X_train[:, 0], q=[0, 25, 50, 75, 100], axis=None, out=None,
                               overwrite_input=False, interpolation='linear', keepdims=False)
    print()
    print(percentile)
    """
    [-0.10722563 -0.0382074   0.00538306  0.03807591  0.11072668]
    """
    

    5.多项式变换

    4个特征的度为2的多项式转换公式为:


    (百度)

    然后比如数据为(1,4)大小的数组,[[1,2,3,4]]

    # 多项式转换
    poly = PolynomialFeatures(degree=2, interaction_only=False, include_bias=True)
    X = np.array([[1, 2, 3, 4]])
    polyed = poly.fit_transform(X)
    print(polyed)
    print()
    """
    [[  1.   1.   2.   3.   4.   1.   2.   3.   4.   4.   6.   8.   9.  12.
       16.]]
       """
    print("{},{}, {}".format(polyed.shape, np.max(polyed), np.min(polyed)))
    """
    (1, 15),16.0, 1.0
    """
    
    1. 自定义函数转换

    就是你可以用任意你定义的函数,把数据变换到另一个值,看代码:

    # 自定义函数转换
    transformer = FunctionTransformer(func=np.log1p, inverse_func=None, validate=True,
                                      accept_sparse=False, pass_y='deprecated',
                                      kw_args=None, inv_kw_args=None)
    
    transformered = transformer.transform(X)
    print()
    print("{},\n {}".format(X[0], transformered[0]))
    print(np.log1p(0.03807591))
    """
    
    [ 0.03807591  0.05068012  0.06169621  0.02187235 -0.0442235  -0.03482076
     -0.04340085 -0.00259226  0.01990842 -0.01764613],
     [ 0.03736891  0.04943769  0.05986782  0.02163659 -0.04523118 -0.03544146
     -0.04437083 -0.00259563  0.01971284 -0.01780367]
     0.0373689130909
     """
    

    下面对几个常用的模型做个分类,需要说明的是,通常归一化之后,效果会变好,但是到底归一不归一,没有一个确定的说法,还是要用结果说话,所以经常有人在微信群里问,某某某个模型要不要归一化,其实你去试试不就知道了,归一化做一遍,不归一化做一遍,做个比较就知道需不需要归一化了。

    需要归一化的模型有

    
    神经网络,标准差归一化
    
    支持向量机,标准差归一化
    
    线性回归,可以用梯度下降法求解,需要标准差归一化
    
    PCA
    
    LDA
    
    聚类算法基本都需要
    
    K近邻,线性归一化,归一到[0,1]区间内。 
    
    逻辑回归
    

    不需要归一化的模型:

    
    决策树:  每次筛选都只考虑一个变量,不考虑变量之间的相关性,所以不需要归一化。
    
    随机森林:不需要归一化,mtry为变量个数的均方根。
    
    朴素贝叶斯
    

    需要正则化的模型:

    Lasso
    
    Elastic Net
    

    完!

    相关文章

      网友评论

        本文标题:[机智的机器在学习] 机器学习中的归一化和正则化问题

        本文链接:https://www.haomeiwen.com/subject/plieqftx.html