Python机器学习:使用scikit-learn进行数据预处理

数据预处理

sklearn.preprocessing包提供了几个数据预处理中常用的功能和变换器,用于将原始特征向量更改为更适合进行机器学习模型的形式。一般来说,数据的标准化使得机器学习算法更加显著,如果数据集中存在一些离散值,显然对数据进行稳定的缩放或转换显然是很有必要的。

标准化

数据集的标准化对scikit-learn中实现的大多数机器学习算法来说是一个必备的前提,如果个别特征或多或少看起来与标准正态分布(具有零均值和单位方差)不是十分类似,那么这些数据的在算号发中的表现会显得差强人意。在实际应用中,我们经常忽略特征的分布情况,直接使用均值对某个特征进行中心化,再通过除以非常量特征的标准差进行缩放。

sklearn.preprocessing中使用函数scale()实现对数组形式的数据集进行标准化

from sklearn import preprocessing
import numpy as np
x = np.array([[1.,-1.,2.],[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.])

sklearn.preprocessing模块还提供了一个实用类StandarScaler,它实现了转化器的API来计算训练集上的平均值和标准差,以便以后能够在测试集上重新应用相同的变换。

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

缩放类对象可以在新的数据集上实现和训练集相同的缩放操作:

x_test = [[-1.,1.,0.]]
scaler.transform(x_test)
array([[-2.44948974,  1.22474487, -0.26726124]])

也可以通过在构造函数:class:StandarScaler中传入参数with_mean=False或者with_std=False来取消中心化或缩放操作。

将特征缩放至特定范围内

一种标准化的实现是将特征缩放到给定的最小值和最大值之间(通常在[0,1]之间),或者也可以将每个特征的最大绝对值转换为单位大小,分别使用MinMaxScalerMaxAbsScaler实现。进行此类缩放的目的是实现特征极小方差的鲁棒性以及在稀疏矩阵中保留零元素。(鲁棒性:表征控制系统对特性或参数扰动的不敏感性)

min_max_scaler = preprocessing.MinMaxScaler()
x_min_max = min_max_scaler.fit_transform(x)
x_min_max
array([[0.5       , 0.        , 1.        ],
       [1.        , 0.5       , 0.33333333],
       [0.        , 1.        , 0.        ]])

同样的转换可以被用在在训练过程中不可见的测试数据,实现和训练数据一致的缩放和移位操作

x_t = np.array([[-3.,-1.,4.]])
x_t_min_max = min_max_scaler.transform(x_t)
print(x_t_min_max)
[[-1.5         0.          1.66666667]]

通过检查缩放器(scaler)的属性,来观察在训练集中学习到的转换操作的基本性质:

min_max_scaler.scale_
array([0.5       , 0.5       , 0.33333333])
min_max_scaler.min_
array([0.        , 0.5       , 0.33333333])

MaxAbsScaler的工作原理与MinMAXScaler非常相似,但是他只是通过除以每个特征的最大值将训练数据特征缩放至[-1,1]之间,这意味着,训练数据应该是已经是零中心化或者是稀疏数据。

max_abs_scaler = preprocessing.MaxAbsScaler()
x_maxabs = max_abs_scaler.fit_transform(x)
x_maxabs
array([[ 0.5, -1. ,  1. ],
       [ 1. ,  0. ,  0. ],
       [ 0. ,  1. , -0.5]])
x_test_maxabs = max_abs_scaler.transform(x_t)
x_test_maxabs
array([[-1.5, -1. ,  2. ]])
max_abs_scaler.scale_
array([2., 1., 2.])

缩放稀疏矩阵

中心化稀疏矩阵会破坏数据的稀疏结构,因此一般不会使用。但是缩放稀疏矩阵是极具意义的,尤其是当几个特征在不同的量级范围时。MaxAbsScaler以及maxabs_scale是专为缩放数据而设计的,并且也是缩放数据的推荐方法。

缩放有离群值的数据

当数据包含许多异常值时,使用均值和方差缩放可能并不是一个很好的选择。这种情况下,可以使用 robust_scale 以及 RobustScaler进行缩放。它们对你的数据的中心和范围使用更有鲁棒性的估计。

非线性转换

类似于缩放,QuantileTransformer类将每个特征缩放在同样的范围或分布下。通过执行一个秩转换能够使异常的分布平滑化,并且能够比缩放更少的收到离群值的影响。但是,它会使特征间及特征内的关联和距离失真。QuantileTransformer 类以及 quantile_transform 函数提供了一个基于分位数函数的无参数转换,将数据映射到了零到一的均匀分布上

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
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)
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([9.99999998e-08, 2.38738739e-01, 5.09009009e-01, 7.43243243e-01,
       9.99999900e-01])

还可以在具有类似形式的独立测试集上确认:

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.25012513, 0.47972973, 0.6021021 , 0.94144144])

也可以通过设置output_distribution='normal'将转换后的数据映射到正态分布。

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.31491491, 2.02982983, 1.01491491, 0.1       ],
       [4.32982983, 2.05965966, 1.02982983, 0.1       ],
       ...,
       [7.84034034, 4.34034034, 6.84034034, 2.5       ],
       [7.87017017, 4.37017017, 6.87017017, 2.5       ],
       [7.9       , 4.4       , 6.9       , 2.5       ]])

归一化

归一化缩放单个样本以具有单位范数的过程,如果使用二次行驶(如点积或任何其他核函数)来量化任何样本的相似度,归一化将显得及其出色。使用normalize对数据集进行归一化处理。Normalization主要思想是对每个样本计算其p-范数,然后对该样本中每个元素除以该范数,这样处理的结果是使得每个处理后样本的p-范数(l1-norm,l2-norm)等于1。范数是泛函分析中定义的一个基本概念,定义在赋范线性空间中,且满足非负性,齐次性,三角不等式。常被用于度量某个向量空间中每个向量的长度和大小。最常用的范数是P范数:若x=[x_1,x_2,...,x_n]^T,那么我们将形如||x||_p=(|x_1|^p+|x_2|^p+...+|x_n|^p)^{\frac{1}{p}}的距离称为P范数。

x_normalize = preprocessing.normalize(x,norm='l1')
x_normalize[:5]
array([[0.5       , 0.34313725, 0.1372549 , 0.01960784],
       [0.51578947, 0.31578947, 0.14736842, 0.02105263],
       [0.5       , 0.34042553, 0.13829787, 0.0212766 ],
       [0.4893617 , 0.32978723, 0.15957447, 0.0212766 ],
       [0.49019608, 0.35294118, 0.1372549 , 0.01960784]])

二值化

特征二值化是将数值特征用阈值过滤得到布尔值的过程。在文字处理中即使归一化计数(术语频率)和TD-IDF值特征在实践中表现稍好一些,处于简化概率估计的考虑,常常会选择使用二值化特征值。

binarizer = preprocessing.Binarizer().fit(x)
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.]])

分类特征编码

在机器学习中,特征经常不是数据型而是分类型,虽然可以将这些分类型特征编码成整数,但是这些整数特征并不能在scikit-learn的估计器中使用,因为输入的是整数特征,估计器会认为类别之间是有序的,但实际却是无序的。故一般使用one-of-K或ono-hot编码进行分类特征转换。sklearn使用preprocessing.OneHotEncoder()实现,该函数使用m个可能值转换为m值化特征,将分类特征的每个元素转化为一个值。

enc = preprocessing.OneHotEncoder()
l = [[0,0,3],[1,1,0],[0,2,1],[1,0,2]]
enc.fit(l)
OneHotEncoder(categorical_features='all', dtype=<class 'numpy.float64'>,
       handle_unknown='error', n_values='auto', sparse=True)
# 使用相同模型训练给出的数据集
enc.transform([[0,1,3]]).toarray()
array([[1., 0., 0., 1., 0., 0., 0., 0., 1.]])

默认情况下,每个特征使用几维的数值由数据集自动推断。当然,也可以通过参数n_values来直接指定。

缺失值补插

因为诸多因素,有时候我们得到的数据往往包含缺失,这些缺失值被编码成空格、NANs,或者其它占位符。由于这些数据集不能被scikit-learn算法所兼容,因为大多数的机器学习算法默认数组中的元素都是数值,每个元素都有自己的意义。对于一些没有价值的数据,处理的基本策略是直接舍弃整行或整列包含缺失值的数据。当然,最好的办法还是从已有的数据中推断出缺失的值。scikit-learn使用Imputer类估算缺失值,使用缺失值所在的行、列中的平均值、中位数或者众数来填充,这种处理方式显然是有点粗糙的,如果需要更高的要求可以使用scipyinterpolate中的插值函数进行估计,也可以使用回归分析进行预测。这里不再详细说明,可以参考数据预处理

from sklearn.preprocessing import Imputer
imp = Imputer(missing_values='NaN',strategy='mean',axis=0)
h = [[1,2],[np.nan,3],[7,6]]
imp.fit(h)
Imputer(axis=0, copy=True, missing_values='NaN', strategy='mean', verbose=0)
t = [[np.nan,2],[6,np.nan],[7,6]]
imp.transform(t)
array([[4.        , 2.        ],
       [6.        , 3.66666667],
       [7.        , 6.        ]])

Imputer也支持稀疏矩阵

import scipy.sparse as sp
i = sp.csc_matrix([[1,2],[0,3],[7,6]])
imp = Imputer(missing_values=0,strategy='mean',axis=0)
imp.fit(i)
Imputer(axis=0, copy=True, missing_values=0, strategy='mean', verbose=0)
i_test = sp.csc_matrix([[0,2],[6,0],[7,6]])
imp.transform(i_test)
array([[4.        , 2.        ],
       [6.        , 3.66666667],
       [7.        , 6.        ]])

需要注意的是,在第二个例子中缺失值被编码为0,隐式的存储在矩阵中。

生成多项式特征

在机器学习中,通过增加一些输入数据的非线性特征来增加模型的复杂度通常是十分有效的,一个比较简单的实现就是使用多项式特征。

from sklearn.preprocessing import PolynomialFeatures
q = np.arange(6).reshape(3,2)
poly = PolynomialFeatures(2)
print(q)
poly.fit_transform(q)
[[0 1]
 [2 3]
 [4 5]]





array([[ 1.,  0.,  1.,  0.,  0.,  1.],
       [ 1.,  2.,  3.,  4.,  6.,  9.],
       [ 1.,  4.,  5., 16., 20., 25.]])

显然,特征已从(X_1,X_2)转换为(1,X_1,X_2,X_1^2,X_1,X_2,X_2^2)

在一些情况下,只需要特征间的交互项,此时可以通过设置interaction_only=True得到:

w = np.arange(9).reshape(3,3)
print(w)
poly = PolynomialFeatures(degree=3,interaction_only=True)
poly.fit_transform(w)
[[0 1 2]
 [3 4 5]
 [6 7 8]]





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_1,X_2,X_3)转换为(1,X_1,X_2,X_3,X_1X_2,X_1X_3,X_2X_3,X_1X_2X_3)

自定义转换器

在机器学习中,如果想要将一个函数转化为一个转换器来协助数据清理或处理,可以使用FunctionTransformer将任意函数实现为转换器。如,构建一个实现日志转换的转换器。

from sklearn.preprocessing import FunctionTransformer
transformer = FunctionTransformer(np.log1p)
s = np.array([[0,1],[2,3]])
transformer.transform(s)
array([[0.        , 0.69314718],
       [1.09861229, 1.38629436]])

本文是作者学习sklearn时的笔记,更多详细内容,请参考scitik-learn

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

推荐阅读更多精彩内容