写点什么

机器学习 | 数据缩放与转换方法(1)

用户头像
披头
关注
发布于: 2021 年 04 月 03 日
机器学习 | 数据缩放与转换方法(1)

数据集标准化是机器学习算法的常规要求,如果某个特征不符合标准正态分布,那么它的学习效果将会变差。如果某个特征的方差比其他特征大几个数量级,那么它就会在机器学习过程中占据主导位置,导致学习器并不能像我们期望的那样,从所有特征中进行学习。


sklearn.preprocessing 包提供了几种实用的转换器功能,可以将原始特征向量转换为更适合机器学习的数据模型。

1 . 数据标准化

1.1 特定范围缩放

比较基础的标准化是将数据缩放至给定的最小值和最大值直接,通常在 0和1 之间,或者将每个特征的最大绝对值转换为单位大小。分布使用 MinMaxScalerMaxAbsScaler 实现。


特点:


  • 提高特征极小方差的鲁棒性

  • 保留稀疏矩阵中零元素


如下是一个将简单的数据集缩放到 [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.        ]])
复制代码


MaxAbsScalerMinMaxScaler 工作原理非常相似,它通过将特征值除以每个特征值的最大值把数据缩放到 [-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 transformthe 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.]])
复制代码

第一部分先到这里了。

发布于: 2021 年 04 月 03 日阅读数: 30
用户头像

披头

关注

还未添加个人签名 2018.11.13 加入

数据科学爱好者,懂点SQL,会点Python,公众号【数据科学探究】

评论

发布
暂无评论
机器学习 | 数据缩放与转换方法(1)