数据预处理
在机器学习算法实践中,往往需要把不同规格的数据转换到同一规格,或者不同分布的数据转换到同一分布,这个过程叫做"无量纲化"。
数据的无量纲化可以是线性的,也可以是非线性的。线性的无量纲化包括"中心化" (Zero-centered or Mean-substraction)处理和缩放处理 (Scale)。中心化的本质是让所有纪录减去一个固定值,即让数据平移到某个位置(通常是0);缩放的本质是通过除以一个固定值,将数据固定挂在某个范围之中,取对数也是一种缩放处理。
Note:决策树即基于决策树的算法不需要对数据进行无量纲化处理,几乎可以应对任何形式的数据。
标准化 (standardization),也称为去均值和方差按比例缩放
数据集的标准化对于 sklearn 中实现的很多机器学习算法来说都是常见的要求。如果个别特征或多或少看起来不像是标准正态分布 (具有零均值和单位方差),那么它们的表现能力可能会很差。
在实际过程中,经常会忽略特征的分布形状,直接经过去均值对某个特征进行中心化,再通过除以非常量特征的标准差进行缩放。
函数scale
为数组形状的数据集的标准化提供了一个快捷实现:
sklearn.preprocessing.scale(X, axis=0, with_mean=True, with_std=True, copy=True)
>>> from sklearn import preprocessing
>>> import numpy as np
>>> X_train = np.array([[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]])
>>> X_scaled = preprocessing.scale(X_train)
>>> X_scaled
array([[ 0. ..., -1.22..., 1.33...],
[ 1.22..., 0. ..., -0.26...],
[-1.22..., 1.22..., -1.06...]])
>>> X_scaled.mean(axis=0)
array([0., 0., 0.])
>>> X_scaled.std(axis=0)
array([1., 1., 1.])
预处理 (preprocessing) 模块还提供了一个实用类 StandardScaler
,它对标准化常用的函数进行了分装,常应用于 sklearn.pipeline.Pipeline
的早期步骤:
class sklearn.preprocessing.StandardScaler(copy=True, with_mean=True, with_std=True)
copy=True
:将计算结果进行返回;with_mean
=True: 对数据进行去中心化,即将其转为了均值为0;-
with_std
=True: 对数据进行缩放,使其方差为标准差;常用的属性 (attribute) 和方法 (method):
-
scale_
: 返回该数组的标准差; -
mean_
: 返回原数组的平均值; -
var_
: 返回原数组的方差; -
fit_transform()
: 计算该数组的平均值和方差,并对其进行转换; -
fit()
: 计算该数组的平均值和方差; -
transform()
: 根据平均值和方差 (由调用fit()
方法时计算得出,不包含该数组),转换该数组; -
inverse_transform()
:可将标准化之后的数据反标准化,返回原始数据;
-
>>> X_train = np.array([[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]])
...
>>> scaler = preprocessing.StandardScaler().fit(X_train)
>>> scaler
StandardScaler(copy=True, with_mean=True, with_std=True)
>>> scaler.mean_
array([ 1. ..., 0. ..., 0.33...])
>>> scaler.scale_
array([ 0.81..., 0.81..., 1.24...])
>>> scaler.transform(X_train)
array([[ 0. ..., -1.22..., 1.33...],
[ 1.22..., 0. ..., -0.26...],
[-1.22..., 1.22..., -1.06...]])
StandardScaler()
和 scale()
的计算方法为:
Note:
- 当设置
with_mean = False
时,不对数组去中心化,这是可以用来处理稀疏矩阵,而且能保持其稀疏性。 -
fit()
和fit_transform()
接受的数据必须是二维数据,如果对某个特征向量单独进行标准化,需要首先使用.reshape(-1,1)
将其由一维数组转化为二维数组。
Normalization 将特征向量缩放至特定范围内
另一种标准化方法是将特征数组缩放到某一范围之内,通常为(0,1)或 (-1,1) 之间,可以使用 MinMaxScaler
和 MaxAbsScaler
实现。
class
sklearn.preprocessing.MinMaxScaler
(feature_range=(0, 1), copy=True)class
sklearn.preprocessing.MaxAbsScaler
(copy=True)
这两个类的用法和 StandardScaler
类的用法几乎一样,其对应的函数分别为 minmax_scale()
和 maxabs_scale()
。
其中:MinMaxScaler
类的计算方式为:
MaxAbsScaler
的计算方法为:
Note:MaxAbsScaler
不但可以处理一般矩阵,还可以处理稀疏矩阵,并且能保持其稀疏性。
StandardScaler 与 MinMaxScaler 该如何选择
大多数机器学习算法中,会选择 StandardScaler
来进行特征缩放,因为 MinMaxScaler
对异常值非常敏感。在 PCA、聚类、逻辑回归、支持向量机、神经网络这些算法中,StandardScaler
往往是最好的选择。在不涉及距离度量、梯度、协方差计算以及数据需要被压缩到特定区间时,比如数字图像处理中量化像素强度时,往往会使用 MinMaxScaler
将数据压缩到 [0,1] 区间。
缩放稀疏矩阵
中心化稀疏矩阵会破坏矩阵的稀疏结构,但是对稀疏矩阵进行缩放是有意义的,尤其是当几个特征在不同的量级范围时。
MaxAbsScaler
以及 maxabsscale
是专门为缩放稀疏矩阵而设计的,并且是缩放稀疏矩阵的推荐方法。同时,scale()
和 StanderdScaler
也可以对稀疏矩阵进行缩放,必须设置参数 with_mean=False
,否则会破坏其稀疏性,当数据量很大时,很容易引起 ValueError
的错误。
缩放有离群点 (outflier)的数据
对于带有很多带有离群点的数据,使用均值和方差进行缩放可能不是很好的选择,这时可以使用 robust_scale
函数或者RobustScaler
,它们对于数据的中心和范围使用更有鲁棒性的估计。
sklearn.preprocessing.robust_scale (X, axis=0, with_centering=True, with_scaling=True, quantile_range=(25.0, 75.0), copy=True)
class sklearn.preprocessing.RobustScaler (with_centering=True, with_scaling=True, quantile_range=(25.0, 75.0), copy=True)
RobustScaler
和 robust_scale
也会对数据进行去中心化和缩放,但是使用的数据不是均值和标准差,而是中间值和第一四分位点和第三四分位点,所以可以很好的降低离群点的影响。具体计算方法为:
QuantileTransformer 类
preprocessing.``QuantileTransformer
(n_quantiles=1000, output_distribution='uniform', ignore_implicit_zeros=False, subsample=100000, random_state=None, copy=True)
preprocessing.``quantile_transform
(X, axis=0, n_quantiles=1000, output_distribution='uniform', ignore_implicit_zeros=False, subsample=100000, random_state=None, copy='warn')
QuantileTransformer
类和 quantile_transformer()
函数提供了一个基于分位数函数的无参数转换,能够将数据映射到 [0,1] 区间上的均匀分布,这种变换能够平滑异常分布,比缩放方法受异常值的影响更小,但是它也使特征间及特征内的关联和距离失真。
PowerTransformer 类
在很多机器学习模型中,都会假设数据服从高斯分布,都是实际数据可能会存在偏度等问题,不完全符合高斯分布,这时需要先把数据转换为高斯分布。
PowerTransformer
可以将数据集从任何分布映射到尽可能接近高斯分布,以便稳定方差和最小化偏斜。
preprocessing.``QuantileTransformer
(n_quantiles=1000, output_distribution='uniform', ignore_implicit_zeros=False, subsample=100000, random_state=None, copy=True)
归一化 (Normalization)
"归一化"是缩放单个样本以使其具有单位范数。如果你计划使用二次形式 (比如点积或者任何其他核函数) 来量化任意样本间的相似度,这个过程将会非常有用。
这种假设是"向量空间模型"的根本,经常在文本分类和内容聚类中使用。
Normalizer
类和函数 normalize()
则提供了一个快速简单的方法在类似于数组的数据结构上执行操作,使其具有 l1
或者 l2
范式。
>>> X = [[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]]
>>> X_normalized = preprocessing.normalize(X, norm='l2')
>>> X_normalized
array([[ 0.40..., -0.40..., 0.81...],
[ 1. ..., 0. ..., 0. ...],
[ 0. ..., 0.70..., -0.70...]])
备注:
-
l1
范式是指该样本各个特征值的绝对值之和等于 1,即:; -
l2
范式是指该样本各个特征值的平方和等于 1,即:. - 该类和函数接受一般矩阵和稀疏矩阵作为输入。
处理分类型数据:编码与哑变量
在 sklearn
当中,除了专门用来处理文字的算法,其他算法在 fit()
的时候要求全部数组必须为数值类型。
preprocessing.LabelEncoder()
能够将标签转化为数值类型,范围是 (0,N-1),N是类型数。
Note:该类时标签专用,即专门用来转换 y,因此输入默认是一维数组。
preprocessing.OrdinalEncoder()
特征矩阵专用,能够将分类特征转换为分类数值,输入默认是二维数组。
preprocessing.OrdinalEncoder (categories=auto, dtype=np.float64)
>>> enc = preprocessing.OrdinalEncoder()
>>> X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
>>> enc.fit(X)
OrdinalEncoder(categories='auto', dtype=<... 'numpy.float64'>)
>>> enc.transform([['female', 'from US', 'uses Safari']])
array([[0., 1., 1.]])
这样将类别数据转化为整数特征的变换会带来另一个问题,sklearn 中的估计器会将该特征当做是有序,并且是有一定含义,但实际上是无序的。另一种转换方式是 one-of-K
, 又称为 dummy encoding
。
preprocessing.OneHotEncoder()
对特征进行哑变量编码;把每一个具有 n_categories 个可能取值的 categorical 特征变换为长度为 n_categories 的二进制特征向量,里面只有一个值为 1,其他值为 0。
preprocessing.``OneHotEncoder
(categories='auto', drop=None, sparse=True, dtype=, handle_unknown='error')
如果训练数据集可能缺少部分分类特征,最好设置 handle_unknown=ignore
, 这样在转换过程中遇到未知类别时,就不会报错,而是将其特征全部设置为 0.
>>> enc = preprocessing.OneHotEncoder()
>>> X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
>>> enc.fit(X)
OneHotEncoder(categorical_features=None, categories=None,
dtype=<... 'numpy.float64'>, handle_unknown='error',
n_values=None, sparse=True)
>>> 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.]])
离散化:二值化和bins
离散化是将连续性特征划分为离散特征的方法,进行离散化处理可以给线性模型引入非线性。
preprocessing.Binarizer()
根据阈值将数据 (连续性数据和离散型数据都可以) 二值化 (0 或者 1)。大于阈值的值映射为1,小于或等于阈值的值映射为0.
preprocessing
.Binarizer
(threshold=0.0, copy=True)
>>> binarizer = preprocessing.Binarizer(threshold=1.1)
>>> binarizer.transform(X)
array([[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 0., 0.]])
preprocessing.KBinsDiscretizer()
能够将连续性变量划分到 K 个不同的 bins 当中,转化为分类变量,既可以将其转化为 OrdinalEncoder()
这样的数字分类变量,又可以转换为 One Hot
编码。
preprocessing
.KBinsDiscretizer
(n_bins=5, encode='onehot', strategy='quantile')
>>> X = np.array([[ -3., 5., 15 ],
... [ 0., 6., 14 ],
... [ 6., 3., 11 ]])
>>> est = preprocessing.KBinsDiscretizer(n_bins=[3, 2, 2], encode='ordinal').fit(X)
>>> est.transform(X)
array([[ 0., 1., 1.],
[ 1., 1., 1.],
[ 2., 0., 0.]])
单变量插补
SimpleImpute
类提供了计算缺失值的基本策略,既可以使用常值填充,又可以使用缺失值所在行的统计数据 (平均值、中位数或众数)来计算,同时也支持不同的缺失值编码方式
class
sklearn.impute.SimpleImputer
(missing_values=nan, strategy='mean', fill_value=None, verbose=0, copy=True, add_indicator=False)
missing_values
:缺失值在数据中的体现形式;
strategy
: ‘mean’, ‘median’, ‘most_frequent’, ‘constant’, 决定由平均值,中值或者总数进行填充。
>>> import numpy as np
>>> from sklearn.impute import SimpleImputer
>>> imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')
>>> imp_mean.fit([[7, 2, 3], [4, np.nan, 6], [10, 5, 9]])
SimpleImputer()
>>> X = [[np.nan, 2, 3], [4, np.nan, 6], [10, np.nan, 9]]
>>> print(imp_mean.transform(X))
[[ 7. 2. 3. ]
[ 4. 3.5 6. ]
[10. 3.5 9. ]]
当使用 most_frequent
or constant
策略进行填充时,SimpleImpute
类还支持以 string values
or pandas.Categoricals
表示的分类数据。
>>> import pandas as pd
>>> df = pd.DataFrame([["a", "x"],
... [np.nan, "y"],
... ["a", np.nan],
... ["b", "y"]], dtype="category")
...
>>> imp = SimpleImputer(strategy="most_frequent")
>>> print(imp.fit_transform(df))
[['a' 'x']
['a' 'y']
['a' 'y']
['b' 'y']]