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

2018-04-12 09:29:22 浏览数 (1)

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

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

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

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

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

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

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

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

下同,不在说明。

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

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

代码语言:javascript复制
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.]
 """

或者

代码语言:javascript复制
# 另一种方法
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.]
"""

2. 最大-最小归一化

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

代码语言:javascript复制
# 最大最小归一化,归一化到[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]之间,公式为:

代码语言:javascript复制
# 最大最小归一化,归一化到[-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.        ]
 """

3. 正则化

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

代码语言:javascript复制
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 变换数据的分布

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

代码语言:javascript复制
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]]

代码语言:javascript复制
# 多项式转换
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
"""

6. 自定义函数转换

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

代码语言:javascript复制
# 自定义函数转换
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

完!

0 人点赞