数据集标准化是机器学习算法的常规要求,如果某个特征不符合标准正态分布,那么它的学习效果将会变差。如果某个特征的方差比其他特征大几个数量级,那么它就会在机器学习过程中占据主导位置,导致学习器并不能像我们期望的那样,从所有特征中进行学习。
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_minmaxarray([[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_minmaxarray([[-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_minmaxarray([[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_maxabsarray([[ 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_maxabsarray([[-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_lognormalarray([[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_normalizedarray([[ 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.]])
复制代码
第一部分先到这里了。
评论