前言
sklearn 常用数据预处理方法比较常见的是标准化、归一化还有正则化,这些方法对于机器模型的训练有很大帮助,大多数时候不仅可以提高模型的准确度还可以减少训练时间。
1、 标准化
(1)scale
对每列数据进行快速标准化(z 标准化),以均值为 0,标准差为 1 的正态分布对每列数据进行标准化,应用公式为:
代码:
1 2 3 4 5 |
from sklearn import preprocessing import numpy as np x = np.array([[ 1., -1., 2.],[ 2., 0., 0.],[ 0., 1., -1.]]) x_scaled = preprocessing.scale(x) print(x_scaled) |
输出:
1 2 3 |
[[ 0. -1.22474487 1.33630621] [ 1.22474487 0. -0.26726124] [-1.22474487 1.22474487 -1.06904497]] |
(2)StandardScaler
类似于 Scale,只不过可保存训练集中的均值、方差参数,例如:可以对测试集生成一个 StandardScaler,就有了一个包含均值与方差的标准化的类。这个类可以通过 transform 函数同时标准化训练集与测试集,代码如下:
1 2 3 4 5 |
x = np.array([[ 1., -1., 2.],[ 2., 0., 0.],[ 0., 1., -1.]]) scaler=preprocessing.StandardScaler(copy=True, with_mean=True, with_std=True).fit(x) # 以上面相同参数转换测试集x scaler.transform(x) print(scaler.transform(x)) |
运行输出如下:
1 2 |
[[ 0. 2.44948974 2.13808994] [-2.44948974 -2.44948974 -0.26726124]] |
数据标准化好处:
- 对于公式推导类型机器学习算法来说,可以消除量纲,让不同特征出现在同一个函数内有了计算可比性,可以极大增强准确度(欧式距离)
- 提升收敛速率:对于利用梯度求导的方式求参数的话,数据标准化可以提高收敛速率
2、 归一化
归一化是指可以将特征标准化到指定的最大值和最小值之间,有两个函数:MinMaxScaler or MaxAbsScaler
(1)MinMaxScaler
最小-最大规范化对原始数据进行线性变换,变换到[0,1]区间(也可以是其他固定最小最大值的区间),例如转化到[0,1]之间:
1 2 3 4 |
X_train=np.array([[1.,-1.,2.], [2.,0.,0.], [0.,1.,-1.]]) min_max_scaler=preprocessing.MinMaxScaler(copy=True, feature_range=(0, 1)) X_train_minmax=min_max_scaler.fit_transform(X_train) print(X_train_minmax) |
输出:
1 2 3 |
[[0.5 0. 1. ] [1. 0.5 0.33333333] [0. 1. 0. ]] |
同理,它也可以直接用到后续的测试集中:
1 2 3 |
X_test=np.array([[-3.,-1.,4.]]) X_test_minmax=min_max_scaler.transform(X_test) print(X_test_minmax) |
输出:
1 |
[[-1.5 0. 1.66666667]] |
注意:比较重要的参数是feature_range,这个确定了变换的区间,上面例子中区间为0-1,也可以是其他的,其核心公式为:
1 2 |
X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0)) X_scaled = X_std * (max - min) + min |
(2)MaxAbsScaler
类 MaxAbsScaler 的工作原理非常相似,但是它只通过除以每个特征的最大值的绝对值将训练数据特征缩放至[-1, 1]范围内,这就意味着,训练数据应该是已经零中心化或者是稀疏数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
>>> X_train = np.array([[ 1., -1., 2.], ... [ 2., 0., 0.], ... [ 0., 1., -1.]]) ... >>> max_abs_scaler = preprocessing.MaxAbsScaler() >>> X_train_maxabs = max_abs_scaler.fit_transform(X_train) >>> X_train_maxabs # doctest +NORMALIZE_WHITESPACE^ array([[ 0.5, -1. , 1. ], [ 1. , 0. , 0. ], [ 0. , 1. , -0.5]]) >>> X_test = np.array([[ -3., -1., 4.]]) >>> X_test_maxabs = max_abs_scaler.transform(X_test) >>> X_test_maxabs array([[-1.5, -1. , 2. ]]) >>> max_abs_scaler.scale_ array([ 2., 1., 2.]) |
归一化与标准化相同与不同之处:
- 不同点:归一化是将样本的特征值转换到同一量纲下把数据映射到[0,1]或者[-1, 1]区间内,仅由变量的极值决定,因区间放缩法是归一化的一种。标准化是依照特征矩阵的列处理数据,其通过求 z-score 的方法,转换为标准正态分布,和整体样本分布相关,每个样本点都能对标准化产生影响。
- 相同点:都能取消由于量纲不同引起的误差;都是一种线性变换,都是对向量 X 按照比例压缩再进行平移。
3、 正则化(Normalizer)
正则化:将每个样本缩放到单位范数(每个样本的范数为 1),如果后面要使用如二次型(点积)或者其他核函数方法计算两个样本之间的相似性,这个方法会很有用。
其思想原理是:
注意:要区别对数据集正则化(normalizer)和对损失函数正则化(regular),对损失函数正则化是在损失函数后加一项惩罚项,用来约束模型的复杂度。
查看了一下网上,发现有很多术语是混淆的,比如 normalizer 认为是归一化,而上面提到的归一化方法则认为是特征缩放——标准化的一种。
我认为本质上理解这些方法即可,不用在意其名称什么的。
正则化的不同在于使用的范数不同,下面先介绍一下各种范数,然后再说具体代码。
(1)各种范数
上面三个公式转换为通用范数公式:
暂时只需要向量范数即可,矩阵范数用不到,关于这些范数的解释,可以参考:机器学习中的范数规则化之(一)L0、L1 与 L2 范数
(2)常用的两种正则化 L1 和 L2
L1 正则化:
1 2 3 |
X = [[ 1, -1, 2],[ 2, 0, 0], [ 0, 1, -1]] X_normalized = preprocessing.normalize(X, norm='l1') print(X_normalized) |
输出:
1 2 3 |
[[ 0.25 -0.25 0.5 ] [ 1. 0. 0. ] [ 0. 0.5 -0.5 ]] |
L1 正则化则是变换后每个样本的各维特征的绝对值和为 1:
1 |
0.25+0.25+0.5=1 |
L2 正则化:
1 2 3 |
X = [[ 1, -1, 2],[ 2, 0, 0], [ 0, 1, -1]] X_normalized = preprocessing.normalize(X, norm='l2') print(X_normalized) |
输出:
1 2 3 |
[[ 0.40824829 -0.40824829 0.81649658] [ 1. 0. 0. ] [ 0. 0.70710678 -0.70710678]] |
可以发现对于每一个样本都有,0.4^ 2+0.4^ 2+0.81^2=1,这就是 L2 norm,变换后每个样本的各维特征的平方和为 1。
注意:要将数据集正则化和损失函数的正则化区分开来,损失函数的正则化是添加惩罚项,通过限制模型复杂度来达到降低过拟合的目的。
4、 二值化
二值化指将特征或标签转换为 0 或 1。
(1)特征二值化
特征二值化是将数值特征用阈值过滤得到布尔值的过程。即,给定阈值,将特征转换为 0/1。
1 2 3 4 |
X=[[1.,-1.,2.], [2.,0.,0.], [0.,1.,-1.]] binarizer=preprocessing.Binarizer(copy=True, threshold=0.0).fit(X)# fit does nothing binarizer.transform(X) print(binarizer.transform(X)) |
输出:
1 2 3 |
[[1. 0. 1.] [1. 0. 0.] [0. 1. 0.]] |
参数中 threshold 是阈值,小于阈值的都为 0,大于阈值的都为 1,调整阈值之后:
1 2 3 4 |
X=[[1.,-1.,2.], [2.,0.,0.], [0.,1.,-1.]] binarizer=preprocessing.Binarizer(copy=True, threshold=1.1).fit(X)# fit does nothing binarizer.transform(X) print(binarizer.transform(X)) |
输出:
1 2 3 |
[[0. 0. 1.] [1. 0. 0.] [0. 0. 0.]] |
(2)标签二值化
1 |
lb = preprocessing.LabelBinarizer() |
5、异常值和缺失值
(1)特征中含有异常值
如果您的数据包含了许多异常值,扩展使用数据的均值和方差可能不能很好地工作。在这些情况下,您可以使用 robust_scale 和 RobustScaler 作为替代。他们使用更健壮的中心和范围的估计数据。
1 |
preprocessing.robust_scale |
(2)缺失值处理
由于各种原因,会导致真实世界中数据集会丢失部分值,如银行等。一种解决办法是去掉这些包含丢失值的行,当然,这样的话就会丢弃掉许多数据,因此可以采取更好的策略来填充丢失的数据,例如通过他们已知的数据来推测。
Imputer 提供基本的填充方法,例如使用均值或者中位数填充。当然还有许多其他的方法。
1 2 3 4 5 6 7 |
import numpy as np from sklearn.preprocessing import Imputer imp = Imputer(missing_values='NaN', strategy='mean', axis=0) imp.fit([[1, 2], [np.nan, 3], [7, 6]]) Imputer(axis=0, copy=True, missing_values='NaN', strategy='mean', verbose=0) X = [[np.nan, 2], [6, np.nan], [7, 6]] print(imp.transform(X)) |
输出:
1 2 3 |
[[4. 2. ] [6. 3.66666667] [7. 6. ]] |
通过输出值,可以看到这里补充的值其实用的是[[1, 2], [np.nan, 3], [7, 6]]里面的均值,所以这就相当于用这个数据训练,然后用下面的数据进行测试了。
从上面可以看到缺失值是我们自己指定的,也就是任意值都可以被指定为缺失值,这就相当于替换操作了,指定缺失值为 0:
1 2 3 4 5 6 7 8 |
import scipy.sparse as sp from sklearn.preprocessing import Imputer X = sp.csc_matrix([[1, 2], [0, 3], [7, 6]]) imp = Imputer(missing_values=0, strategy='mean', axis=0) imp.fit(X) Imputer(axis=0, copy=True, missing_values=0, strategy='mean', verbose=0) X_test = sp.csc_matrix([[0, 2], [6, 0], [7, 6]]) print(imp.transform(X_test)) |
输出:
1 2 3 |
[[4. 2. ] [6. 3.66666667] [7. 6. ]] |
其他缺失值处理方法,可以参考:https://sklearn.apachecn.org/docs/master/41
6、生成多项式
在机器学习中,通过增加一些输入数据的非线性特征来增加模型的复杂度通常是有效的。一个简单通用的办法是使用多项式特征,这可以获得特征的更高维度和互相间关系的项。这在 PolynomialFeatures 中实现:
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.]]) |
X 的特征已经从 (X_1, X_2) 转换为 (1, X_1, X_2, X_1^2, X_1X_2, X_2^2)。
在一些情况下,只需要特征间的交互项,这可以通过设置 interaction_only=True 来得到:
1 2 3 4 5 6 7 8 9 10 |
>>> X = np.arange(9).reshape(3, 3) >>> X array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) >>> poly = PolynomialFeatures(degree=3, interaction_only=True) >>> poly.fit_transform(X) array([[ 1., 0., 1., 2., 0., 0., 2., 0.], [ 1., 3., 4., 5., 12., 15., 20., 60.], [ 1., 6., 7., 8., 42., 48., 56., 336.]]) |
X 的特征已经从 (X_1, X_2, X_3) 转换为 (1, X_1, X_2, X_3, X_1X_2, X_1X_3, X_2X_3, X_1X_2X_3) 。
更多数据预处理参考:预处理数据
评论