利用scikit-learn进行机器学习:特征工程(一)数据预处理
对于机器学习,业内早有这样的说法:“数据和特征决定了你机器学习模型效果的上限,而模型和算法只是逐渐逼近这个上限而已。”小编不才,在机器学习方面只尝试过一些简单的数据建模过程,但对这种观点深以为然。在全球数据科学顶级比赛kaggle里面,特征工程往往被众多资深kaggler们所重视,一言以敝之,机器学习算法的效果受益于特征工程工作做得是否充分。
所谓特征工程本质上是一项工程活动,目的是最大限度地从原始数据集中抽取有效特征以供模型和算法使用。具体包括数据预处理、特征选择和降维等三个大的方面,今天这篇文章小编从最开始的数据预处理开始讲起,我们用到的工具就是scikit-learn.
scikit-learn是Python中专门针对机器学习应用而发展起来的一款优秀的开源机器学习框架。从scikit-learn给出的官方文档我们可以看到,scikit-learn将机器学习内容分为六大块:分类、回归、聚类、降维、模型选择与评估以及数据预处理。其中降维和数据预处理的内容均可视为特征工程的内容。下面就开始小编的特征工程第一讲:数据预处理。
数据预处理是特征工程里面最基础也是最重要的内容之一,通常情形下,我们能够拿到的数据很可能不适合直接放入机器学习模型中,通过sklearn提供的preprocessing模块我们可以轻松的实现原始数据的处理。
数据标准化
图片来自:https://www.zhihu.com/question/37069477
数据标准化可以算是最常见的数据预处理方法了。广泛的来讲,数据标准化更多的是指数据的无量纲化,并不仅指均值-标准差化法下的数据标准化方法,也包括极值化法、均值化法等无量纲化方法。通常情况下,数据的标准化处理是必须而且必要的,因为很多时候我们的原始数据集在不同维度特征的尺度(单位)上并不一致,需要通过标准化处理将其转化成具有相同尺度的数据。preprocessing模块中的scale函数提供了数据标准化的基本方法:
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,可以实现对测试集数据的重新使用:
scaler = preprocessing.StandardScaler().fit(X_train)
scalerStandardScaler(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...]])
将该类运用在新的数据集上:
X_test = [[-1., 1., 0.]]
scaler.transform(X_test)
array([[-2.44..., 1.22..., -0.26...]])
另一种数据标准化方法即上文所提到的极值化法,通过将特征值减去最小值(或者是最大值减去特征值)除以极差(最大值减去最小值)将原始数据缩放至指定范围,也是一种较为有效的数据无量纲化方法。preprocessing模块为我们提供了MinMaxScaler类来进行处理:
X_train = np.array([[ 1., -1., 2.],[ 2., 0., 0.],[ 0., 1., -1.]])
min_max_scaler = preprocessing.MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(X_train)
X_train_minmaxarray([[ 0.5,0.,1.],[1.,0.5,0.33333333],[ 0.,1.,0.]])
数据归一化
所谓归一化是缩放单个样本以具有单位范数的过程,这与标准化有着明显的不同。简单来说,标准化是针对特征矩阵的列数据进行无量纲化处理,而归一化是针对数据集的行记录进行处理,使得一行样本所有的特征数据具有统一的标准,是一种单位化的过程。预处理模块中的normalize函数可用来做归一化处理:
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...]])
与前述相同的是,Normalizer 也为我们提供了数据归一化的实用类。
normalizer = preprocessing.Normalizer().fit(X)
normalizer
normalizerNormalizer(copy=True, norm='l2')
normalizer.transform(X)
array([[ 0.40..., -0.40..., 0.81...],[ 1. ..., 0. ..., 0. ...],[ 0. ..., 0.70..., -0.70...]])
normalizer.transform([[-1., 1., 0.]])
array([[-0.70..., 0.70..., 0. ...]])
数据二值化
二值化是将数值特征用阈值过滤得到布尔值的过程,也是连续变量离散化方式的一种。实用类 Binarizer 提供了二值化的基本方法:
X = [[ 1., -1., 2.],[ 2., 0., 0.],[ 0., 1., -1.]]
binarizer = preprocessing.Binarizer().fit(X)
binarizerBinarizer(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.]])
分类特征编码
在实际的机器学习数据中,数据集特征值是分类文本值而不是连续数值的情况居多。一个人的国籍可以有中国、美国、英国等等,scikit-learn 中使用 one-hot 编码,通过OneHotEncoder类来实现分类特征编码:
enc = preprocessing.OneHotEncoder()
enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])
OneHotEncoder(categorical_features='all', dtype=<... '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.]])
缺失值插补
上一篇有关pandas的推送中我们讨论了如何使用pandas进行缺失值的插补方法,fillna函数为pandas数据分析提供了较为灵活的缺失值插补方法。而在 scikit-learn 数据预处理模块中,Inputer 类为我们提供了插补缺失值的基本策略。
比如说用平均值来插补缺失值:
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.]]
>>>>
总结
以上就是 preprocessing 模块中关于数据预处理的基本方法,值得注意的一点是,sklearn中大多数预处理方法都是通过该方法的实用类+fit_transform 方法来实现。当然,还有一些像生成多项式特征、自定义转换器、非线性变换等不太常用的方法这里没有提到,具体可参考scikit-learn的官方文档。
参考资料:
http://scikit-learn.org/stable/modules/preprocessing.html#preprocessing
往期精彩:
利用pandas进行数据分析(一):Series和DataFrame数据结构
使用jupyter notebook搭建数据科学最佳交互式环境
一个数据科学热爱者的学习历程