预处理数据的方法总结(使用sklearn-preprocessing)
12-02 阅读数 3万+
预处理数1.标准化:去均值,方差规模化Standardization标准化:将特征数据的分布调整成标准正太分布,也叫高斯分布,也就是使得数据的均值维0,方差为1.标准化的原因在于如果有些特征的方差过大... 博文 来自: 【人工智能】王小草的博客
1. 标准化Standardization(这里指移除均值和方差标准化)
标准化是很多数据分析问题的一个重要步骤,也是很多利用机器学习算法进行数据处理的必要步骤。
1.1 z-score标准化
z-score标准化指的是将数据转化成均值为0方差为1的高斯分布,也就是通常说的z-score标准化,但是对于不服从标准正态分布的特征,这样做效果会很差。
在实际应用中,我们经常忽视分布的形状,将数据进行z-score标准化。如果不将数据进行标准化处理,在利用机器学习算法(例如SVM)的过程中,如果目标函数中的一个特征的方差的阶数的量级高于其他特征的方差,那么这一特征就会在目标函数中占主导地位,从而“淹没”其他特征的作用。
Python中的scale函数是一种快速进行z-score标准化的方法,能够处理类似于数组结构的数据。Z-score标准化后的数据的均值为0,方差为1。
>>> from sklearn import preprocessing
>>> x = [[1., -1., 2], # 每一行为[feature1, feature2, feature3]
... [2., 0., 0.],
... [0., 1., -1.]]
>>> x_scaled = preprocessing.scale(x)
>>> x_scaled
array([[ 0. , -1.22474487, 1.33630621],
[ 1.22474487, 0. , -0.26726124],
[-1.22474487, 1.22474487, -1.06904497]])
>>> x_scaled.mean(axis=0)
array([ 0., 0., 0.])
>>> x_scaled.std(axis=0)
array([ 1., 1., 1.])
preprocessing模块还提供了一个实用类StandardScaler,这个类实现了一个叫做Transformer的应用程序接口,能够计算训练数据的均值和标准差,从而在训练数据集上再次使用。
>>> scaler = preprocessing.StandardScaler().fit(x)
>>> scaler
StandardScaler(copy=True, with_mean=True, with_std=True)
>>> scaler.mean_
array([ 1. , 0. , 0.33333333])
>>> scaler.scale_
array([ 0.81649658, 0.81649658, 1.24721913])
>>> scaler.transform(x)
array([[ 0. , -1.22474487, 1.33630621],
[ 1.22474487, 0. , -0.26726124],
[-1.22474487, 1.22474487, -1.06904497]])
>>> scaler = preprocessing.StandardScaler().fit(x)
>>> scaler
StandardScaler(copy=True, with_mean=True, with_std=True)
>>> scaler.transform([[-1., 1., 0.]]) # 在其他数据集上使用
array([[-2.44948974, 1.22474487, -0.26726124]])
1.2 将特征数据缩放到一个范围 scale to a range
利用最大值和最小值进行缩放,通常是将数据缩放到0-1这个范围,或者是将每个特征的绝对值最大值缩放到单位尺度,分别利用MinMaxScaler和MaxAbsScaler实现。
使用这一方法的情况一般有两种:
(1) 特征的标准差较小
(2) 可以使稀疏数据集中的0值继续为0
>>> x
[[1.0, -1.0, 2], [2.0, 0.0, 0.0], [0.0, 1.0, -1.0]]
>>> min_max_scaler = preprocessing.MinMaxScaler()
>>> x_scaled_minmax = min_max_scaler.fit_transform(x)
>>> x_scaled_minmax
array([[ 0.5 , 0. , 1. ],
[ 1. , 0.5 , 0.33333333],
[ 0. , 1. , 0. ]])
>>> #这个transformer的实例还能够应用于新的数据集,此时的缩放比例与之前训练集上的缩放比例是相同的。
>>> x_test = np.array([[3., 1., 4.]])
>>> min_max_scaler.transform(x_test)
array([[ 1.5 , 1. , 1.66666667]])
可以查看缩放算子的一些属性:
min_, scale_, data_min_, data_max_, data_range_,
>>> min_max_scaler.scale_ # 缩放比例=1/(max-min)
array([ 0.5 , 0.5 , 0.33333333])
>>> min_max_scaler.min_ # (x-min)/(max-min), 这里min_代表min/(max-min)
array([ 0. , 0.5 , 0.33333333])
MaxAbsScaler与上述用法相似,但是标准化后的数据的取值范围为[-1, 1]。这对于稀疏数据或者是数据中心已经为0的数据很有意义。
>>> x=[[1., -1., 2.], [2., 0., 0.], [0., 1., -1.]]
>>> max_abs_scaler = preprocessing.MaxAbsScaler()
>>> max_abs_scaler.fit_transform(x)
array([[ 0.5, -1. , 1. ],
[ 1. , 0. , 0. ],
[ 0. , 1. , -0.5]])
>>> x_test = [[-2., 4., 2.]]
>>> max_abs_scaler.transform(x_test)
array([[-1., 4., 1.]])
>>> max_abs_scaler.scale_
array([ 2., 1., 2.])
1.3 缩放稀疏数据
将稀疏数据置中有可能破坏数据的稀疏结构。但是将稀疏数据进行缩放是有意义的,特别是对于量纲不同的特征输入。
MaxAbsScaler和maxabs_scale特别适用于缩放稀疏数据。此外,scale和StandardScaler能够处理scipy.sparse矩阵作为输入的情况,此时需要将with_mean设置为False。否则默认的置中操作将会破坏数据的稀疏型,会抛出一个ValueError的错误,而且内存可能会被大量占用造成内存溢出。RobustScaler不适用于稀疏数据的处理,但是它的transform方法可以作用于稀疏数据。
注意,缩放器(scaler)允许输入压缩的稀疏行和稀疏列数据(见scipy.sparse.csr_matrix和scipy.sparse.csc_matrix)任何其他的稀疏输入都会被转化成压缩的稀疏行表示。为了避免不必要的内存占用,建议使用CSR或者CSC表示法。
最后,如果希望置中的数据足够小,可以使用sparse matrices的toarray方法将稀疏的输入数据转化为一个数组。
sklearn.preprocessing.maxabs_scale(X, axis=0, copy=True)
class sklearn.preprocessing.MaxAbsScaler(copy=True) # 这是一个Transformer API
1.4 缩放带有outlier的数据
如果数据中含有异常值,那么使用均值和方差缩放数据的效果并不好。这种情况下,可以使用robust_scale和RobustScaler。
sklearn.preprocessing.robust_scale(X, axis=0, with_centering=True, with_scaling=True, quantile_range=(25.0, 75.0), copy=True)[source]
class sklearn.preprocessing.RobustScaler(with_centering=True, with_scaling=True, quantile_range=(25.0, 75.0), copy=True) # 这是一个Transformer API
这两种方法计算的数据的均值和范围更加可靠。
Scale和StandardScaler能够用于一维数组,这对于缩放回归过程中的的目标/响应变量十分有用。
1.5 置中核矩阵
如果有一个核矩阵(在函数phi定义的特征空间上计算点积得到),那么KernelCenterer能够转移核矩阵,使得在函数phi定义的特征空间中的内积构造的核矩阵能够转移到移除均值后的空间中。
2. 规范化(Normalization)
规范化是指将样本缩放成单位向量。如果需要使用二次方程,比如点积或者其他核方法计算样本对之间的相似性,那么这一过程非常有用。
这一假设是常用于文本分类和内容聚类的向量空间模型的基础。
normalize函数提供了一个处理单个结构类似数组的数据集的快速简单的方法,可以使用1范数l1或者2范数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执行相同的操作(虽然fit方法这里是没有意义的,因为规范化是对于每个样本独立进行的)。
>>> x=[[1., -1., 2.], [2., 0., 0.], [0., 1., -1.]]
>>> normalizer = preprocessing.Normalizer().fit(x)
>>> normalizer
Normalizer(copy=True, norm='l2')
>>> 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. ]])
对于稀疏的输入数据,normalize和Normalizer可以接受非稀疏数组类型和稀疏矩阵类型左右的输入。稀疏数据将被转化为压缩的稀疏行表示法。
3. 二值化
3.1 特征二值化
这一过程就是定义一个阈值,然后得到数值特征的布尔值。这对于假设输入数据服从多元伯努利分布的概率估计量非常有用。这在文本处理过程中也非常常见。
实力类Binarizer可以实现这一过程。同样的,fit函数没有意义。
>>> x=[[1., -1., 2.], [2., 0., 0.], [0., 1., -1.]]
>>> binarizer = preprocessing.Binarizer().fit(x)
>>> binarizer
Binarizer(copy=True, threshold=0.0)
>>> binarizer.transform(x)
array([[ 1., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.]])
>>> binarizer = preprocessing.Binarizer(threshold=1.1)
>>> binarizer.transform(x)
array([[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 0., 0.]])
此外,在没必要使用Transformer API时,也提供了binarize方法进行转化。binarize和Binarizer都可以处理稀疏输入。
4. 分类特征编码
当某些特征不是连续取值而是分类数据时,就需要对分类特征进行编码,比如人的性别有[“男”, “女”]之分,国籍可以是[“中国”, “英国”, “美国”],使用的浏览器可能为[“FireFox”, “Chrome”, “Safari”, “IE”]。这样的特征可以分别用不同的整数进行标记,比如[“男”, “女”]分表表示成[0, 1],[“中国”, “英国”, “美国”]分别表示成[0, 1, 2],[“FireFox”, “Chrome”, “Safari”, “IE”]表示为[0, 1, 2, 3]
但是,这种整数表示方法不能直接用于scikit-learn估计量,因为这一算法包希望输入是连续的变量,因此就会将不同的种类理解成不同的大小。解决这一问题的一个方法是使用one-of-K或者one-hot编码,通过OneHotEncoder实现。这一估计量将每个含有m个取值的分类特征转化为m个二值特征,其中只有一个处于active状态。
>>> enc = preprocessing.OneHotEncoder()
>>> enc.fit([[0,0,3],[1,1,0],[0,2,1],[1,0,2]])
OneHotEncoder(categorical_features='all', dtype=<class 'float'>,
handle_unknown='error', n_values='auto', sparse=True)
>>> enc.transform([[0,1,3]]).toarray()
array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]]) # 一共9位
>>> # feature1只有0,1两个取值,因此是两位
>>> # feature2有0,1,2三个取值,因此是三位
>>> # feature3有0,1,2,3四个取值,因此是四位
每个特征的分类个数默认上根据输入数据集自动计算。但是也可以通过设置参数n_values进行人为设定。在上述例子中,三个分类属性的可选值数量分别为2,3,4。特别是当训练数据集在某个可能取值上没有训练样本时,需要人为制定分类数量。例如:
>>> enc = preprocessing.OneHotEncoder(n_values=[2, 3, 4])
>>> enc.fit([[1,2,3],[0,2,0]])
OneHotEncoder(categorical_features='all', dtype=<class 'float'>,
handle_unknown='error', n_values=[2, 3, 4], sparse=True)
>>> enc.transform([[1 , 0, 0]]).toarray()
array([[ 0., 1., 1., 0., 0., 1., 0., 0., 0.]])
5. 推定缺失数据
很多情况下,真实的数据集中会存在缺失值,此时数据集中会采用空格、NaNs或者其他占位符进行记录。但是scikit-learn的输入变量应该为数值型,此时需要对缺失值进行处理。一种策略是将存在缺失值的整条记录直接删除。但是这样做可能会丢失一部分有价值的信息。更好的一种方法是推定缺失数据,例如根据已经数据推算缺失的数据。
Imputer类能够提供一些处理缺失值的基本策略,例如使用缺失值所处的一行或者一列的均值、中位数或者出现频率最高的值作为缺失数据的取值。下边举一个使用缺失值所处行的均值作为缺失值的例子:
>>> 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))
[[ 4. 2. ]
[ 6. 3.666...]
[ 7. 6. ]]
Imputer也支持稀疏矩阵作为输入:
>>> import scipy.sparse as sp
>>> 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))
[[ 4. 2. ]
[ 6. 3.666...]
[ 7. 6. ]]
6. 产生多项式特征
在输入数据存在非线性特征时,这一操作对增加模型的复杂度十分有用。一种常见的用法是生成多项式特征,能够得到特征的高阶项和相互作用项。利用PolynomialFeatures实现:
>>> 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=(X1, X2)被转化为(1, X1, X2, X1^2, X1X2, X2^2)。
在有些情况下,我们只需要相互作用项,此时可以通过设定interaction_only=True实现:
>>> 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=(X1, X2, X3)被转化为to (1, X1, X2, X3, X1X2, X1X3, X2X3, X1X2X3)。
多项式特征经常用于使用多项式核函数的核方法(比如SVC和KernelPCA)。
7. 定制转换器
我们经常希望将一个Python的函数转变为transformer,用于数据清洗和预处理。可以使用FunctionTransformer方法将任意函数转化为一个Transformer。比如,构建一个对数log的Transformer:
>>> import numpy as np
>>> from sklearn.preprocessing import FunctionTransformer
>>> transformer = FunctionTransformer(np.log1p)
>>> X = np.array([[0, 1], [2, 3]])
>>> transformer.transform(X)
array([[ 0. , 0.69314718],
[ 1.09861229, 1.38629436]])
5
0条评论
下一篇
12-02 阅读数 3万+
预处理数1.标准化:去均值,方差规模化Standardization标准化:将特征数据的分布调整成标准正太分布,也叫高斯分布,也就是使得数据的均值维0,方差为1.标准化的原因在于如果有些特征的方差过大... 博文 来自: 【人工智能】王小草的博客