sklearn-Preprocessing Data 数据预处理

官方文档: https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing

Sklearn.preprocessing包提供了很多的的函数和转换器的类,便于用户将原始数据的特征向量转换成适合后面部分要用到的形式。

通常演算法使用标准化的数据效果会更好,如果数据集种存在离群点的话,鲁棒性的scaler和transformer将很适合使用,不同的scaler、transformer和normalizer在同一数据集上也会产生不同的效果,所以我们需要根据使用的数据集选择合适的预处理工具。

Standardization, or mean removal and variance scaling

对原始的数据集进行标准化是很多演算法的基本要求,如果独立的特征的分布不是像标准正态分布【N(0,1)的高斯分布】的类型,演算法的效果可能就会很差。

在实际应用中我们经常忽略分布的形状,只是通过去除每个特征的平均值,将数据中心化,然后通过将非的常量的特征除以它们的标准差来进行缩放。

例如,在演算法的目标函数中使用的许多元素(如支持向量机的RBF核或线性模型的l1和l2正则化器)都假设所有的特征都以0为中心,并且具有相同顺序的方差。如果某一个特征的方差比其他特征的方差大几个数量级,那么它可能会决定目标函数,使估计器无法像预期的那样正确地从其他特征中学习。

注:[在线性回归中选用误差平方和作为误差函数,其实就是将误差假定为了0均值的高斯正态分布。这也就是为什么还会存在sigmoid逻辑回归(以伯努利分布分析误差),以及softmax等一般线性回归(以指数分布分析误差)。]

preprocessing进一步提供了一个工具类StandarScaler使用Tansformer来计算训练集上的平均值和标准偏差,这样就可以在测试集上重复使用达到相同的转换的效果。StandarScaler适合应用在sklearn.pipeline.Pipeline。

可以通过将with_mean=False或with_std=False传递给StandardScaler的构造函数来不使用中心化和放缩。

Scaling features to a range

另一种标准化方法是将特征缩放到给定的最小值和最大值之间,通常在0和1之间,或者将每个特征的最大绝对值缩放到单位大小。这可以分别使用MinMaxScaler或MaxAbsScaler实现。这样做是为了在特征值具有非常小的标准差时提高鲁棒性,以及在稀疏数据中保留零项。可以查看scaler的参数(比如scale_、min_等)来内在的理解这种转换的本质。

如果MinMaxScaler指定了feature_range = (min,max),将使用下main的代码完成scale

X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
X_scaled = X_std * (max - min) + min

MaxAbsScaler的工作方式和MinMaxScaler非常类似,但它是将训练数据放缩到位于[- 1,1]的范围内,方法是用每个特征值除以它的最大值,它适用于已经已经中心化的数据或稀疏数据为中心的数据。如果不想使用通过创建对象的方式来使用,也可以使用minmax_scale和maxabs_scale函数。

Scaling sparse data

对稀疏数据进行中心化会破坏数据的稀疏结构,但是当数据集的不同特征的规模相差较大时,使用scale就是有意义的。

MaxAbsScaler和maxabs_scale是专门用于放缩稀疏数据。只要with_mean=False被显式传递给构造函数,scale和StandardScaler就可以接受scipy.sparse矩阵作为输入,。否则会抛出ValueError异常,因为以默认的方式中心化会破坏数据的稀疏性。RobustScaler不适合稀疏输入,但可以使用transform方法进行转换。如果中心数据足够小,使用稀疏矩阵的toarray方法显式地将输入转换为数组。

Scaling data with outliers

如果数据包含许多离群点,那么使用上面的办法效果就不会太好。这时可以使用robust_scale和RobustScaler作为替换,它们会对数据的中心和范围使用做出更可靠的估计。

注:
1. 数据的normalize和standardize不是必须的,需要我们根据不同的数据集做出决定
2. 有时不能在预处理阶段单独的去中心化或是放缩数据,因为在后面的过程中可能会需要特征之间原始的某些依赖关系,可以将sklearn.decomposition.PCA 的whiten = True来移除特征之间的线性相关性
3. 上面所有的函数都可以接收一维数组的输入

Centering kernel matrices

如果你有一个内核K的内核矩阵,通过Φ定义的函数来计算特征空间的内积,KernelCenterer可以变换核矩阵,这样的话它就包含特征空间的内积定义,然后使用φ移除特征空间的均值。

Non-linear transformation

Mapping to a Uniform distribution就像scaler一样,QuantileTransformer将所有特征缩放到在相同的已知范围或分布中。然而通过执行秩变换,它平滑了不寻常的分布,比放缩方法受异常值的影响更小,但它会扭曲特征之间的相关性和距离。

QuantileTransformer和quantile_transform提供了一种基于分位数函数的非参数变换,将数据映射到一个值介于0和1之间的均匀分布:

Mapping to a Gaussian distribution

在许多建模场景中,都希望数据集的特征是正态的。幂变换是一组参数单调变换,其目的是将数据从任意分布映射到尽可能接近高斯分布,以便稳定方差和最小化偏差。PowerTransformer提供了Yeo-Johnson transform 和 Box-Cox transform两个幂转换函数,其中Yeo-Johnson transform通过以下公式给出
sklearn-Preprocessing Data 数据预处理_第1张图片
Box-Cox transform由以下公式给出
sklearn-Preprocessing Data 数据预处理_第2张图片
Box-Cox只能应用于严格正数据。在这两种方法,转换由λ参数化,λ由最大似然估计决定。默认情况下,PowerTransformer将对转换后的输出变成零均值、单位方差的标准正态分布。

也可以使用QuantileTransformer通过设置output_distribution='normal’将数据映射到正态分布。

因此,输入的中值变成了以0为中心的输出的平均值。对正常输出进行裁剪,使输入的最小值和最大值(分别对应于1e-7和1 - 1e-7分位数)在转换过程中不会变成无穷大。

Normalization

标准化是将单个样本缩放为具有单位范数的过程。如果打算使用二次形式(如点积)或任何其他kernel来量化任何一对样本的相似性,那么这个过程将非常有用。这一基于向量空间模型的假设在文本分类和聚类中经常使用。

normalize函数提供了一种快速便捷的方式在单个数组类型的数据集上进行操作,使用L1或是L2正则。perprocessing模块进一步的提供了类Normalizer使用Transformer API来达到相同的效果(这里fit方法是无效的)。

normalize和Normalizer都接受密集数组数据和系数矩阵数据输入。对于稀疏输入,在将数据输入到高效的Cython例程之前,数据被转换为压缩的稀疏行表示(参见scipy.sparse.csr_matrix)。为了避免不必要的内存副本,建议选择上游的CSR表示。

Encoding categorical features

特征通常不是连续的,而是一些分类的数据,比如一个人可以有这些征:
[“male”, “female”], [“from Europe”, “from US”, “from Asia”],[“uses Firefox”, “uses Chrome”, “uses Safari”, “uses Internet Explorer”]。这些特征可以有效地被编码为整数,比如:
[“male”, “from US”, “uses Internet Explorer”]可以表示成[0,1,3],[“female”, “from Asia”, “uses Chrome”]可以表示成[1,2,1]。

要将分类特征转换为此类整数代码,可以使用OrdinalEncoder。该估计器将每个分类特征转换为整数的一个新特征(0到n_categories - 1)。

然而,并不是所有的scikit-learn估计器都可以直接使用这种整数表示,因为它们需要连续的输入,并且会将类别解释为有序的,这通常是不需要的。

将分类特征转换为scikit-learn估计器可以使用的特征的另一种可能性是使用one-of-K,也称为one-hot编码或dummy编码。这种类型的编码可以通过OneHotEncoder获得,它将具有n_categories可能值的每个分类特征转换为n_categories二进制特征,其中一个为1,其他的都为0。默认情况下,每个特性可以接受的值自动从数据集中推断出来,可以在categories_属性中找到,也可以使用categories显式地指定这一点,比如:

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])

如果训练数据可能缺少分类特性,通常最好指定handle_unknown=‘ignore’,而不是像上面那样手动设置类别。当指定handle_unknown='ignore’并在转换过程中遇到未知类别时,不会出现错误,但是该特性的one-hot编码那一列都是零(handle_unknown='ignore’只被one-hot编码支持)。
enc = preprocessing.OneHotEncoder(handle_unknown=‘ignore’)

Discretization(离散化)

离散化(也称为量化或分箱)提供了一种将连续特性划分为离散值的方法。某些具有连续特征的数据集可以从离散化中受益,因为离散化可以将连续属性的数据集转换为只有标称属性的数据集。one-hot编码的离散化特性可以使模型更具表达性,同时保持可解释性。例如使用discretizer进行预处理可以将非线性引入线性模型。

K-bins discretization

KBinsDiscretizer离散器的特点为k个等宽箱:

est = preprocessing.KBinsDiscretizer(n_bins=[3, 2, 2], encode='ordinal').fit(X)

默认情况下,输出是由one-hot编码到稀疏矩阵,它可以使用encode参数配置。对于每个特性,在fit期间计算bin边,并与bin的数量一起定义间隔。

结果数据集包含序数属性,这些属性可以在sklearn.pipeline.Pipeline中进一步的使用。离散化类似于为连续数据构造直方图。然而,直方图侧重于计算属于特定类别的特征,而离散化则侧重于为这些类别分配特值。KBinsDiscretizer实现了不同的分箱策略,可以使用strategy参数进行选择。“uniform”策略使用等宽箱。“分位数(quantile)”策略使用分位数值在每个特性中具有相同填充的容器。“kmeans”策略基于对每个特性分别执行的k-means聚类过程来定义容器。

Feature binarization

特征二值化是对数值特征进行阈值化得到布尔值的过程。假设输入数据是多变量伯努利分布分布,这对于后面的概率估计器是有用的。

在文本处理领域中,使用二进制特征值(可能是为了简化概率推理)也很常见,即使标准化计数(即术语频率)或TF-IDF值的特征在实践中通常表现得稍好。

对于Normalizer,类Binarizer用于sklearn.pipeline.Pipeline的早期阶段。fit方法没有任何作用,因为每个样本都是独立于其他样本进行处理的。在使用Binarizer时可以设置threshold参数来调整阈值。对于StandardScaler和Normalizer类,预处理模块提供了一个伴生函数binarize,以便在不需要transformer API时使用。当k = 2时,Binarizer与KBinsDiscretizer类似,当bin边缘位于threshold值处时。

binarize和Binarizer都接受密集数组数据和系数矩阵数据输入。对于稀疏输入,在将数据输入到高效的Cython例程之前,数据被转换为压缩的稀疏行表示(参见scipy.sparse.csr_matrix)。为了避免不必要的内存副本,建议选择上游的CSR表示

Imputation of missing values

Imputation of missing values. ImpleImputer类提供了计算缺失值的基本策略。可以使用提供的常量值来计算缺失值,或者使用缺失值所在的每一列的统计信息(平均值、中值或最常见的)。这个类还允许不同的缺失值编码。

Generating polynomial features

通常,通过考虑输入数据的非线性特征来增加模型的复杂性是很有用的。多项式特征是一种简单而常用的方法,它可以得到特征的高阶和相互作用项。它是用PolynomialFeatures实现的。

From sklearn.preprocessing import PolynomialFeatures
PolynomialFeatures(2).fit_transform(x)

特征X可以被从 (X1,X2) 转换成(1,X1,X2,X12,X1X2,X22)。在某些情况下,只需要特性之间的交互项,可以通过设置interaction_only=True得到:特征从 (X1,X2,X3)转换为(1,X1,X2,X3,X1X2,X1X3,X2X3,X1X2X3)。

Custom transformers

通常,您希望将现有的Python函数转换为转换器以帮助数据清理或处理。您可以使用FunctionTransformer从任意函数实现转换器。通过设置check_inverse=True并在转换之前调用fit,可以确保func和inverse_func互为倒数。

官方示例代码:

# 数据预处理

from sklearn import preprocessing
from sklearn.datasets import load_iris
from sklearn.model_selection import  train_test_split
import numpy as np
#

X_train = np.array([[ 1., -1.,  2.],
                    [ 2.,  0.,  0.],
                    [ 0.,  1., -1.]])

# standardization
X_scaled = preprocessing.scale(X_train)

print (X_scaled)
print ("mean = ",X_scaled.mean(axis = 0))
print ("std =",X_scaled.std(axis = 0))

# StandardScaler
scaler = preprocessing.StandardScaler().fit(X_train)
print (scaler)
print ("scaler.mean_ = ",scaler.mean_)
print ("scaler.scale_ = ",scaler.scale_)
scal_X_train = scaler.transform(X_train)
print ("scal_X_train = \n " ,scal_X_train)

# MinMaxScaler
min_max_scaler = preprocessing.MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(X_train)
print ("X_train_minmax = \n",X_train_minmax)

# X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
# X_scaled = X_std * (max - min) + min

# MaxAbsScaler
max_abs_scaler = preprocessing.MaxAbsScaler()
X_train_maxabs = max_abs_scaler.fit_transform(X_train)
print ("X_train_maxabs = \n",X_train_maxabs) 

#####
# Mapping to a Uniform distribution
iris = load_iris()
X,y = iris.data, iris.target
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)
print (np.percentile(X_train[:, 0], [0, 25, 50, 75, 100])) 

# Mapping to a Gaussian distribution
# Box-Cox transform
from sklearn.preprocessing import PowerTransformer
pt = PowerTransformer(method='box-cox', standardize=False)
X_lognormal = np.random.RandomState(616).lognormal(size=(3, 3))
print ("X_lognormal = ",X_lognormal)                                         
box_cox_X_lognormal = pt.fit_transform(X_lognormal)
print ("box_cox_X_lognormal = ",box_cox_X_lognormal)

## # Normalization
# normalize
X = [[ 1., -1.,  2.],
     [ 2.,  0.,  0.],
     [ 0.,  1., -1.]]
X_normalized = preprocessing.normalize(X, norm='l2')
print ("X_normalized = \n",X_normalized)

# Normalizer
#print (preprocessing.normalizer.transform(X))                            
#print (preprocessing.normalizer.transform([[-1.,  1., 0.]])) 


from sklearn import preprocessing

# OrdinalEncoder
enc = preprocessing.OrdinalEncoder()
X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
enc.fit(X)  

print (enc.transform([['female', 'from US', 'uses Safari']]))

# OneHotEncoder
enc = preprocessing.OneHotEncoder()
X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
print (enc.fit(X))  
print (enc.transform([['female', 'from US', 'uses Safari'],
               ['male', 'from Europe', 'uses Safari']]).toarray())
print ("ecn_categories_ = \n",enc.categories_)

# categories=
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])
X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
enc.fit(X) 
print (enc.transform([['female', 'from Asia', 'uses Chrome']]).toarray())


# handle_unknown='ignore':忽略缺失值
enc = preprocessing.OneHotEncoder(handle_unknown='ignore')
X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
enc.fit(X) 
print (enc.transform([['female', 'from Asia', 'uses Chrome']]).toarray())

# KBinsDiscretizer
X = np.array([[ -3., 5., 15 ],
              [  0., 6., 14 ],
              [  6., 3., 11 ]])
est = preprocessing.KBinsDiscretizer(n_bins=[3, 2, 2], encode='ordinal').fit(X)
print (est.transform(X))

# Binarizer
X = [[ 1., -1.,  2.],
     [ 2.,  0.,  0.],
     [ 0.,  1., -1.]]

binarizer = preprocessing.Binarizer().fit(X)  # fit does nothing
print (binarizer)
print (binarizer.transform(X))

# Generating polynomial features
import numpy as np
from sklearn.preprocessing import PolynomialFeatures

# PolynomialFeatures
X = np.arange(6).reshape(3, 2)
print (X)
poly = PolynomialFeatures(2)
print (poly.fit_transform(X))

# nteraction_only=True:只保留特征间的相互关系
X = np.arange(9).reshape(3, 3)
print (X)                                                 
poly = PolynomialFeatures(degree=3, interaction_only=True)
print (poly.fit_transform(X)) 

# Custom transformaers
import numpy as np
from sklearn.preprocessing import FunctionTransformer
transformer = FunctionTransformer(np.log1p, validate=True)
X = np.array([[0, 1], [2, 3]])
print (transformer.transform(X))


#### OUTPUT
[[ 0.         -1.22474487  1.33630621]
 [ 1.22474487  0.         -0.26726124]
 [-1.22474487  1.22474487 -1.06904497]]
mean =  [0. 0. 0.]
std = [1. 1. 1.]
StandardScaler(copy=True, with_mean=True, with_std=True)
scaler.mean_ =  [1.         0.         0.33333333]
scaler.scale_ =  [0.81649658 0.81649658 1.24721913]
scal_X_train = 
  [[ 0.         -1.22474487  1.33630621]
 [ 1.22474487  0.         -0.26726124]
 [-1.22474487  1.22474487 -1.06904497]]
X_train_minmax = 
 [[0.5        0.         1.        ]
 [1.         0.5        0.33333333]
 [0.         1.         0.        ]]
X_train_maxabs = 
 [[ 0.5 -1.   1. ]
 [ 1.   0.   0. ]
 [ 0.   1.  -0.5]]
[4.3 5.1 5.8 6.5 7.9]
X_lognormal =  [[1.28331718 1.18092228 0.84160269]
 [0.94293279 1.60960836 0.3879099 ]
 [1.35235668 0.21715673 1.09977091]]
box_cox_X_lognormal =  [[ 0.49024349  0.17881995 -0.1563781 ]
 [-0.05102892  0.58863196 -0.57612414]
 [ 0.69420008 -0.84857822  0.10051454]]
X_normalized = 
 [[ 0.40824829 -0.40824829  0.81649658]
 [ 1.          0.          0.        ]
 [ 0.          0.70710678 -0.70710678]]
[[0. 1. 1.]]
OneHotEncoder(categorical_features=None, categories=None,
       dtype=, handle_unknown='error',
       n_values=None, sparse=True)
[[1. 0. 0. 1. 0. 1.]
 [0. 1. 1. 0. 0. 1.]]
ecn_categories_ = 
 [array(['female', 'male'], dtype=object), array(['from Europe', 'from US'], dtype=object), array(['uses Firefox', 'uses Safari'], dtype=object)]
[[1. 0. 0. 1. 0. 0. 1. 0. 0. 0.]]
[[1. 0. 0. 0. 0. 0.]]
[[0. 1. 1.]
 [1. 1. 1.]
 [2. 0. 0.]]
Binarizer(copy=True, threshold=0.0)
[[1. 0. 1.]
 [1. 0. 0.]
 [0. 1. 0.]]
[[0 1]
 [2 3]
 [4 5]]
[[ 1.  0.  1.  0.  0.  1.]
 [ 1.  2.  3.  4.  6.  9.]
 [ 1.  4.  5. 16. 20. 25.]]
[[0 1 2]
 [3 4 5]
 [6 7 8]]
[[  1.   0.   1.   2.   0.   0.   2.   0.]
 [  1.   3.   4.   5.  12.  15.  20.  60.]
 [  1.   6.   7.   8.  42.  48.  56. 336.]]
[[0.         0.69314718]
 [1.09861229 1.38629436]]

你可能感兴趣的:(Scikit-learn)