数据集标准化是机器学习算法的常规要求,如果某个特征不符合标准正态分布,那么它的学习效果将会变差。如果某个特征的方差比其他特征大几个数量级,那么它就会在机器学习过程中占据主导位置,导致学习器并不能像我们期望的那样,从所有特征中进行学习。
sklearn.preprocessing
包提供了几种实用的转换器功能,可以将原始特征向量转换为更适合机器学习的数据模型。
1 . 数据标准化
1.1 特定范围缩放
比较基础的标准化是将数据缩放至给定的最小值和最大值直接,通常在 0和1
之间,或者将每个特征的最大绝对值转换为单位大小。分布使用 MinMaxScaler
和 MaxAbsScaler
实现。
特点:
如下是一个将简单的数据集缩放到 [0, 1]
的示例:
>>> from sklearn import preprocessing
>>> import numpy as np
>>>
>>> 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. ]])
复制代码
使用训练数据学习到的转换特性可以很方便的应用到测试数据
>>> X_test = np.array([[-3., -1., 4.]])
>>> X_test_minmax = min_max_scaler.transform(X_test)
>>> X_test_minmax
array([[-1.5 , 0. , 1.66666667]])
复制代码
参数 feature_range=(min, max)
可以将数据集缩放至固定范围,完整公式为:
X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
X_scaled = X_std * (max - min) + min
复制代码
应用示例:
>>> from sklearn import preprocessing
>>> import numpy as np
>>>
>>> X_train = np.array([[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]])
>>>
>>> min_max_scaler = preprocessing.MinMaxScaler(feature_range=(0, 2))
>>> X_train_minmax = min_max_scaler.fit_transform(X_train)
>>> X_train_minmax
array([[1. , 0. , 2. ],
[2. , 1. , 0.66666667],
[0. , 2. , 0. ]])
复制代码
MaxAbsScaler
与 MinMaxScaler
工作原理非常相似,它通过将特征值除以每个特征值的最大值把数据缩放到 [-1, 1]
范围内。
使用 MaxAbsScaler
方法操作示例数据:
>>> from sklearn import preprocessing
>>> import numpy as np
>>>
>>> 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
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.])
复制代码
1.2 稀疏数据缩放
中心化稀疏数据会破坏数据的稀疏结构,通常不会这么做。但是,缩放稀疏数据的输入还是有意义的,尤其是当不同特征具有不同的量级范围的时候。
MaxAbsScaler
转为缩放稀疏数据而设计,也是推荐使用的方法。然而,StandardScaler
也能够接受 scipy.sparse
作为输入,只要在构造器中传入参数 with_mean=False
即可。否则会出现 ValueError
错误,因为默认的中心化会破坏稀疏性,且经常因为分配过多的内存而导致任务崩溃。RobustScaler
也不能适应稀疏输入,但你可以在处理稀疏输入时使用 transform
方法。
1.3 有离群值数据缩放
如果数据集包含较多的异常值,可以采用 RobustScaler
方法进行处理,它可以对数据集的中心和范围进行更具有鲁棒性的评估。
2. 非线性转换
2.1 映射到均匀分布
QuantileTransformer
方法提供了一个基于分位数函数的无参数转换,将数据映射到了零到一的均匀分布上:
>>> from sklearn import preprocessing
>>> import numpy as np
>>>
>>> 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])
复制代码
应用分位数转换之后,这些特征元素就会接近于之前定义的百分位数:
>>> np.percentile(X_train_trans[:, 0], [0, 25, 50, 75, 100])
array([0. , 0.23873874, 0.50900901, 0.74324324, 1. ])
复制代码
也可以在测试集上进行确认:
>>> np.percentile(X_test[:, 0], [0, 25, 50, 75, 100])
array([4.4 , 5.125, 5.75 , 6.175, 7.3 ])
>>>
>>>
>>> np.percentile(X_test_trans[:, 0], [0, 25, 50, 75, 100])
array([0.01351351, 0.25 , 0.47747748, 0.60472973, 0.94144144])
复制代码
2.2 映射到正态分布(高斯分布)
在许多建模场景中,需要数据集中特征的正态化特征。幂变换是一种实现形式。幂变换是一类参数化的单调转换,目的是将数据从任何分布映射为近似于高斯分布,以便稳定方差和最小化偏斜。
PowerTransformer
目前提供两个这样的幂变换, Yeo-Johnson transform
和 the Box-Cox transform
。其中 Box-Cox
仅能应用于严格的正数。
使用 Box-Cox
将样本数据从对数正态分布转换为正态分布的示例:
>>> from sklearn import preprocessing
>>> import numpy as np
>>>
>>> pt = preprocessing.PowerTransformer(method='box-cox', standardize=False)
>>> X_lognormal = np.random.RandomState(616).lognormal(size=(3, 3))
>>> X_lognormal
array([[1.28331718, 1.18092228, 0.84160269],
[0.94293279, 1.60960836, 0.3879099 ],
[1.35235668, 0.21715673, 1.09977091]])
>>>
>>> pt.fit_transform(X_lognormal)
array([[ 0.49024349, 0.17881995, -0.1563781 ],
[-0.05102892, 0.58863195, -0.57612415],
[ 0.69420009, -0.84857822, 0.10051454]])
复制代码
我们也可以使用用类 QuantileTransformer
(通过设置 output_distribution='normal'
)把数据转换成一个正态分布。下面是将其应用到 iris dataset
上的结果:
>>> quantile_transformer = preprocessing.QuantileTransformer(
... output_distribution='normal', random_state=0)
>>> X_trans = quantile_transformer.fit_transform(X)
>>> quantile_transformer.quantiles_
array([[4.3, 2. , 1. , 0.1],
[4.4, 2.2, 1.1, 0.1],
[4.4, 2.2, 1.2, 0.1],
...,
[7.7, 4.1, 6.7, 2.5],
[7.7, 4.2, 6.7, 2.5],
[7.9, 4.4, 6.9, 2.5]])
复制代码
3. 归一化
归一化 是 缩放单个样本以具有单位范数 的过程。如果你计划使用二次方形式(如点积或任何其他核函数)来量化任何样本间的相似度,则此过程将非常有用。
这个观点基于 向量空间模型(
Vector Space Model)
,经常在文本分类和内容聚类中使用。
函数 normalize
提供了一个快速简单的方法在类似数组的数据集上执行操作,使用 l1 、 l2 范式 或者最大范式:
>>> X = [[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]]
>>> X_normalized = preprocessing.normalize(X, norm='l2')
>>>
>>> X_normalized
array([[ 0.40824829, -0.40824829, 0.81649658],
[ 1. , 0. , 0. ],
[ 0. , 0.70710678, -0.70710678]])
复制代码
preprocessing.Normalizer()
工具类使用 Transformer API
实现了相同的操作。
>>> normalizer.transform(X)
array([[ 0.40824829, -0.40824829, 0.81649658],
[ 1. , 0. , 0. ],
[ 0. , 0.70710678, -0.70710678]])
>>>
>>> normalizer.transform([[-1., 1., 0.]])
array([[-0.70710678, 0.70710678, 0. ]])
复制代码
4. 类别特征编码
在机器学习中,特征经常不是连续的数值型而是枚举值。举个栗子,一个人的样本特征:["male", "female"]
, ["from Europe", "from US", "from Asia"]
, ["uses Firefox", "uses Chrome", "uses Safari", "uses Internet Explorer"]
等。这些特征能够被编码成整数,比如 ["male", "female"]
可以编码为 [0, 1]
。
OrdinalEncoder
可以完成这种转换 。 这个转换器把每一个 categorical feature
变换成 一个新的整数数字特征 ( 0 到 n_categories - 1
):
>>> 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-of-K
也叫 one-hot
或者 dummy
。OneHotEncoder
可以实现这种转换,它把把每一个具有 n_categories
个可能取值的 categorical
特征变换为长度为 n_categories
的二进制特征向量,里面只有一个地方是 1
,其余位置都是 0
。
应用示例如下:
>>> enc = preprocessing.OneHotEncoder()
>>> X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
>>> enc.fit(X)
OneHotEncoder()
>>>
>>> enc.transform([['female', 'from US', 'uses Safari'],
... ['male', 'from Europe', 'uses Safari']]).toarray()
array([[1., 0., 0., 1., 0., 1.],
[0., 1., 1., 0., 0., 1.]])
复制代码
通过 `` 方法可以获取每个特征的特征值:
>>> enc.categories_
[array(['female', 'male'], dtype=object), array(['from Europe', 'from US'], dtype=object), array(['uses Firefox', 'uses Safari'], dtype=object)]
复制代码
可以使用参数categories_
显式地指定这一点。我们的数据集中有两种性别、四种可能的大陆和四种 web 浏览器:
>>> genders = ['female', 'male']
>>> locations = ['from Africa', 'from Asia', 'from Europe', 'from US']
>>> browsers = ['uses Chrome', 'uses Firefox', 'uses IE', 'uses Safari']
>>> enc = preprocessing.OneHotEncoder(categories=[genders, locations, browsers])
>>> # Note that for there are missing categorical values for the 2nd and 3rd
>>> # feature
>>> X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
>>> enc.fit(X)
OneHotEncoder(categories=[['female', 'male'],
['from Africa', 'from Asia', 'from Europe',
'from US'],
['uses Chrome', 'uses Firefox', 'uses IE',
'uses Safari']])
>>>
>>> enc.transform([['female', 'from Asia', 'uses Chrome']]).toarray()
array([[1., 0., 0., 1., 0., 0., 1., 0., 0., 0.]])
复制代码
如果训练数据可能包含缺失的枚举特征,设置 handle_unknown='ignore'
通常比像上面那样手动设置 categories
要好。当 handle_unknown='ignore'
被指定而在转换的过程中碰到了未知的枚举特征值,不会产生任何错误,但是该特征的 one-hot
编码列将会被全部置 0
。(仅 one-hot
编码支持 handle_unknown='ignore'
特性 )。
>>> enc = preprocessing.OneHotEncoder(handle_unknown='ignore')
>>> X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
>>> enc.fit(X)
OneHotEncoder(handle_unknown='ignore')
>>>
>>> enc.transform([['female', 'from Asia', 'uses Chrome']]).toarray()
array([[1., 0., 0., 0., 0., 0.]])
复制代码
第一部分先到这里了。
评论