sklearn 数据预处理

数据预处理

官方文档

在机器学习算法实践中,往往需要把不同规格的数据转换到同一规格,或者不同分布的数据转换到同一分布,这个过程叫做"无量纲化"。

数据的无量纲化可以是线性的,也可以是非线性的。线性的无量纲化包括"中心化" (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() 的计算方法为:

z=(x-\mu)/s

Note:

  • 当设置 with_mean = False 时,不对数组去中心化,这是可以用来处理稀疏矩阵,而且能保持其稀疏性。
  • fit()fit_transform() 接受的数据必须是二维数据,如果对某个特征向量单独进行标准化,需要首先使用 .reshape(-1,1)将其由一维数组转化为二维数组。

Normalization 将特征向量缩放至特定范围内

另一种标准化方法是将特征数组缩放到某一范围之内,通常为(0,1)或 (-1,1) 之间,可以使用 MinMaxScalerMaxAbsScaler实现。

class sklearn.preprocessing.MinMaxScaler(feature_range=(0, 1), copy=True)

class sklearn.preprocessing.MaxAbsScaler(copy=True)

这两个类的用法和 StandardScaler类的用法几乎一样,其对应的函数分别为 minmax_scale()maxabs_scale()

其中:MinMaxScaler类的计算方式为:

x_{std}=\frac{x-min(x)}{max(x)-min(x)}

x_{scaled}=x_{std}*(max(x)-min(x))+min(x)

MaxAbsScaler 的计算方法为:

x^,=\frac{x}{|max(x)|}

NoteMaxAbsScaler 不但可以处理一般矩阵,还可以处理稀疏矩阵,并且能保持其稀疏性。

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)

RobustScalerrobust_scale也会对数据进行去中心化和缩放,但是使用的数据不是均值和标准差,而是中间值和第一四分位点和第三四分位点,所以可以很好的降低离群点的影响。具体计算方法为:
x_{scaled}=\frac{x-x.median()}{x.quantile(0.75)-x.quantile(0.25)}

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,即:\sum |x_i|=1;
  • l2 范式是指该样本各个特征值的平方和等于 1,即:\sum x_i^2=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']]
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容