Python数据分析之scikit-learn与数据预处理​

简介: Python数据分析之scikit-learn与数据预处理​

1 引言


预处理操作是机器学习整个周期中必不可少的一个过程,也是最能快速改善模型性能的一个过程,往往稍微转换一下特征属性的形态,就能得到性能的极大提升。当然,数据预处理绝对也是耗时最长的一个过程,这一过程不仅要求洞悉整个数据集结构分布,还要探查每一个特征属性细节情况,并作出应对处理,使数据以最适合的状态传输给模型。


针对预处理操作,sklearn中提供了许多模块工具,灵活使用工具可以让数据预处理轻松很多。


本文简要介绍数据预处理中的一些主要方法,并结合sklearn中提供的模块进行实践。


2 无量纲化


对于大部分机器学习任务而言,对原始数据进行无量纲化是是建模前的必不可少的一个环节。通过无量纲化,可以消除量纲不一致对模型造成的不良影响。标准化和归一化是最为常见的两种无量纲化方法,下面分别展开介绍这两种方法。


2.1 标准化


标准化对数据的分布的进行转换,使其符合某种分布(一般指正态分布)的一种特征变换。一般而言,标准化都是指通过z-score的方法将数据转换为服从均值为0,标准差为1的标准正态分布数据,通过如下公式进行转换:

image.png

式中,μ和σ是指x所在特征属性集的均值和标准差。


(1)sklearn.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_train各列,我们会发现,均值和方差都已经标准化:


X_train.mean(axis=0)
array([1.        , 0.        , 0.33333333])
X_scaled.std(axis=0)
array([1., 1., 1.])


(2)sklearn.preprocessing.StandardScaler类实现归一化


除了scale方法外,在sklearn.preprocessing模块中还提供有一个专门的类用于实现标准化:StandardScaler,StandardScaler类会自动计算实例化类时传入的训练集的均值、标准差,并将这些信息保留,这也就意味着,对训练集的标准化方式可以复用,例如对测试集和预测样本进行同样的标准化。所以,一般来说,更加建议使用StandardScaler类来实现标准化。

# 传入一个训练集,实例化StandarScaler类
scaler = preprocessing.StandardScaler()
scaler.fit(X_train)  # 收集标准化信息,均值,标准差
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])


创建StandarScaler类实例后,需要通过类中的transform方法对X-train进行标准化:

scaler.transform(X_train)
array([[ 0.        , -1.22474487,  1.33630621],
       [ 1.22474487,  0.        , -0.26726124],
       [-1.22474487,  1.22474487, -1.06904497]])


StandardScaler类中还提供有一个fit_transform方法,这个方法合并了fit和transform两个方法的功能,同时根据传入的数据集收集标准化信息,并将标准化方案应用于传入的训练集:

scaler = preprocessing.StandardScaler()
x_train = scaler.fit_transform(X_train)
x_train
array([[ 0.        , -1.22474487,  1.33630621],
       [ 1.22474487,  0.        , -0.26726124],
       [-1.22474487,  1.22474487, -1.06904497]])


假设现在有一个测试样本,那么,也可以通过transform方法将标准化方案应用于测试样本上:

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


2.2 归一化


归一化是指对数据的数值范围进行特定缩放,但不改变其数据分布的一种线性特征变换。大多数场景下,归一化都是将数据缩放到[0,1]区间范围内,计算公式如下:

x′=x−minmax−min 式中,min和max是x所属特征集合的最小值和最大值。可见,这种归一化方式的最终结果只受极值的影响。


(1)sklearn.preprocessing.minmax_scale方法实现归一化。

X_train = np.array([[ 1., -1.,  2.],
                    [ 2.,  0.,  0.],
                    [ 0.,  1., -1.]])
X_train = preprocessing.minmax_scale(X_train)
X_train
array([[0.5       , 0.        , 1.        ],
       [1.        , 0.5       , 0.33333333],
       [0.        , 1.        , 0.        ]])


(2)sklearn.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_minmax
array([[0.5       , 0.        , 1.        ],
       [1.        , 0.5       , 0.33333333],
       [0.        , 1.        , 0.        ]])


使用训练好的min_max_scaler对新的测试样本进行归一化:

X_test = np.array([[-3., -1.,  4.]])
X_test_minmax = min_max_scaler.transform(X_test)
X_test_minmax
array([[-1.5       ,  0.        ,  1.66666667]])


我们知道,归一化是将特征属性值缩放到[0,1]范围,但在某些特殊的场景下,我们需要将特征属性缩放到其他范围,MinMaxScaler类通过feature_range参数也提供了这一功能,feature_range参数接受一个元组作为参数,默认值为(0,1)。


X_train = np.array([[ 1., -1.,  2.],
                    [ 2.,  0.,  0.],
                    [ 0.,  1., -1.]])
min_max_scaler = preprocessing.MinMaxScaler(feature_range=(10,20))
X_train_minmax = min_max_scaler.fit_transform(X_train)
X_train_minmax
array([[15.        , 10.        , 20.        ],
       [20.        , 15.        , 13.33333333],
       [10.        , 20.        , 10.        ]])


(3)sklearn.preprocessing.MaxAbsScaler类实现归一化


MaxAbsScaler是专门为稀疏数据做归一化设计的,通过特征值除以整个特征集合最大绝对值实现,最终将数据投影到[-1, 1]范围内,对原来取值为0的数据并不会做出变换,所以不会影响数据的稀疏性。


最后来总结一下标准化和归一化。标准化是依照特征矩阵的列处理数据,其通过求z-score的方法,转换为标准正态分布,和整体样本分布相关,每个样本点都能对标准化产生影响,而归一化是将样本的特征值转换到同一量纲下把数据映射到指定区间内,仅由变量的极值决定,所以对异常值较为敏感。标准化和归一化都是一种线性变换,都是对向量x按照比例压缩再进行平移。无论是标准化还是归一化,都可以将数据无量纲化,消除不同量纲对结果的影响,同时都可以加过模型的收敛速度。标准化与归一化之间如何选择呢?


大多数机器学习算法中,会选择StandardScaler来进行特征缩放,因为MinMaxScaler对异常值非常敏感。在PCA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardScaler往往是最好的选择。


MinMaxScaler在不涉及距离度量、梯度、协方差计算以及数据需要被压缩到特定区间时使用广泛,比如数字图像处理中量化像素强度时,都会使用MinMaxScaler将数据压缩于[0,1]区间之中。若是归一化时需要保留数据的稀疏性,则可以使用MaxAbscaler归一化。在大多数情况下,建议先试试看StandardScaler,效果不好换MinMaxScaler。

另外,这里再提一下正则化(Normalization),很多资料把正则化与归一化、标准化放到一起讨论,虽然正则化也是数据预处理方法的一种,但我并不认为正则化是无量纲化方法。正则化通过某个特征值除以整个样本所有特征值的范数计算,使得整个样本范数为1,通常在文本分类和聚类中使用较多。


sklearn中提供preprocessing.normalize方法和preprocessing.Normalizer类实现:


X_train = np.array([[ 1., -2.,  2.],
                    [ 2.,  0.,  0.],
                    [ 0.,  1., -1.]])
max_abs_scaler = preprocessing.MaxAbsScaler()
X_train_max_abs = max_abs_scaler.fit_transform(X_train)
X_train_max_abs
array([[ 0.5, -1. ,  1. ],
       [ 1. ,  0. ,  0. ],
       [ 0. ,  0.5, -0.5]])
X_train = np.array([[ 1., -1.,  2.],
                    [ 2.,  0.,  0.],
                    [ 0.,  1., -1.]])
nor = preprocessing.Normalizer()
X_train_nor = nor.fit_transform(X_train)
X_train_nor
array([[ 0.40824829, -0.40824829,  0.81649658],
       [ 1.        ,  0.        ,  0.        ],
       [ 0.        ,  0.70710678, -0.70710678]])


3 缺失值处理


由于各种各样的原因,我们所面对的数据经常是有所缺失的,然而sklearn中实现的各个算法都假设数据没有缺失为前提,如果直接用缺失数据跑算法影响最终结果不说,也容易产生各种异常,所以在数据预处理阶段,对缺失值进行处理是很有必要的。对于缺失值处理,直接删除包含缺失值的特征属性或者样本是最简单的方法,但是这种方法却也将其他部分信息抛弃,在很多情况下,特别是数据样本不多、数据价值大时,未免得不偿失。在sklearn中,提供了诸多其他处理缺失值的方案,例如以均值、中位数、众数亦或者是指定值填充缺失值等,这些方案都在sklearn.impute模块中提供的SimpleImputer类中实现,SimpleImputer类参数如下:

640.png

import numpy as np
from sklearn.impute import SimpleImputer
imp = SimpleImputer(missing_values=np.nan, strategy='mean')  # 指定缺失值为nan,以均值填充
imp.fit([[1, 2], [np.nan, 3], [7, 6]])
X = [[np.nan, 2], [6, np.nan], [7, 6]]
imp.transform(X)
array([[4.        , 2.        ],
       [6.        , 3.66666667],
       [7.        , 6.        ]])
imp = SimpleImputer(missing_values=0, strategy='constant', fill_value=1)  # 指定缺失值为0,指定以常数1填充
imp.fit([[5, 2], [4, 0], [7, 6]])
X = [[0, 2], [6, 0], [7, 6]]
imp.transform(X)
array([[1, 2],
       [6, 1],
       [7, 6]])


4 离散型特征属性处理


很多时候,我们所要处理的特征属性未必是连续型的,也可能是离散型,以衣服为例,款式(男款、女款),大小(X、XL、XXL),颜色(绿色、红色、白色),都是离散型特征属性。对于这类离散型特征属性,需要编码之后才能用来建模。离散型特征属性值可以分为两种:


(1)数字编码整数编码是指对离散型属性以整数来标识,例如色泽这一特征中,以整数“0”标识“男款”,整数“1”标识“女款”。sklearn中提供了LabelEncoder和OrdinalEncoder两个类用以实现对数据的不同取值以数字标识。LabelEncoder和OrdinalEncoder会自动根据提供的训练数据进行统计,分别对每个特征属性从0开始编码,不同的是,LabelEncoder类一次只能对一个一维数组(一个特征属性)编码,而OrdinalEncoder能同时对各个特征属性编码:

enc = preprocessing.LabelEncoder()  # 只能接受一个一维数组
X = ['红色', '白色', '绿色']
enc.fit(X)
X_ = enc.transform(X)
X_
array([1, 0, 2])
enc = preprocessing.OrdinalEncoder()  # 可以同时多通过特征属性编码
X = [['女款', 'X', '绿色'], ['女款', 'XL', '红色'], ['男款', 'XXL', '白色']]
enc.fit(X)
X_ = enc.transform(X)
X_
array([[0., 0., 2.],
       [0., 1., 1.],
       [1., 2., 0.]])
enc.inverse_transform(X_)  # 可以使用inverse_transform逆转
array([['女款', 'X', '绿色'],
       ['女款', 'XL', '红色'],
       ['男款', 'XXL', '白色']], dtype=object)


但在很多模型中,使用整数编码并不合理,特别是在聚类这类需要计算空间距离的算法模型。仔细观察上面编码,颜色这一属性有三种取值(绿色、红色、白色),分别以(2,1,0)表示,颜色之间是没有大小意义的,但以三个数字表示后,就赋予了三种属性值大小上的意义,且在算法计算距离时,绿色(2)到白色(0)的距离比红色(1)到白色(0)大,这是不合理的。对于这类取值没有大小意义的离散型特征属性,有一种更加合适的编码方式:独热编码。


(2)独热编码


独热编码即 One-Hot 编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。sklearn中提供了OneHotEncoder类用以实现对数据的独热编码:

enc = preprocessing.OneHotEncoder()
X = [['女款', 'X', '绿色'], ['女款', 'XL', '红色'], ['男款', 'XXL', '白色']]
enc.fit(X)
enc.transform([['男款', 'XL', '绿色']]).toarray()
array([[0., 1., 0., 1., 0., 0., 0., 1.]])

在上述输出结果中,特征属性有多少种取值经过独热编码后就扩展为多少个维度,以款

式为例,经过独热编码后,扩展为两个维度,第一维中1表示是女款,0表示非女款。在实例化OneHotEncoder类时,可以通过categories参数指定各特征属性的所有类别,这样即使存在训练数据中没有出现的类别,在后续出现时也能正确编码:

style = ['女款', '男款']
size = [ 'X','XL','XXL']
color = ['绿色','红色','白色']
enc = preprocessing.OneHotEncoder(categories=[style, size, color])
X = [['女款', 'X', '绿色'], ['女款', 'XL', '红色']]
enc.fit(X)
enc.transform(X).toarray()
array([[1., 0., 1., 0., 0., 1., 0., 0.],
       [1., 0., 0., 1., 0., 0., 1., 0.]])
enc.transform([['男款', 'XXL', '白色']]).toarray()  # 男款,XXL,白色三个属性值均为在X中出现,但是可以正确编码
array([[0., 1., 0., 0., 1., 0., 0., 1.]])


创建好OneHotEncoder类实例并通过训练数据后,就可以对后续的数据进行独热编码,但是,有时候却不可避免地出现categories和训练数据集中都未出现过的取值,这时候继续编码就会抛出异常。为了防止这一情况发生,我们可以在创建OneHotEncoder实例时,传入参数handle_unknown='ignore',这样的话,如果出现某一特征属性值未在categories和训练数据集中出现过,通过热独编码时,该特征属性多对应的维度都会以0来填充。

style = ['女款', '男款']
size = [ 'X','XL']
color = ['绿色','红色']
enc = preprocessing.OneHotEncoder(categories=[style, size, color],handle_unknown='ignore')
X = [['女款', 'X', '绿色'], ['女款', 'XL', '红色']]
enc.fit(X)
enc.transform([['男款', 'XXL', '白色']]).toarray()  # XXL, 白色在categories和X中都为出现过
array([[0., 1., 0., 0., 0., 0.]])


独热编码解决了离散型属性难以有效刻画的问,在一定程度上也起到了扩充特征的作用,它的值只有0和1,不同的类型存储在垂直的空间。当类别的数量很多时,特征空间会变得非常大。在这种情况下,一般可以用PCA来减少维度。而且one hot encoding+PCA这种组合在实际中也非常有用。


5 连续型特征属性离散化


有时候,将连续型特征属性离散化能够显著提高模型的表现力。连续型特征属性离散化包括二值化和分段等方法。


(1)二值化


二值化是指通过一个阈值对属性值进行划分,当小于这个阈值时,将值映射为0,大于阈值时映射为1。二值化是对文本计数数据的常见操作,分析人员可以决定仅考虑某种现象的存在与否。它还可以用作考虑布尔随机变量的估计器的预处理步骤(例如,使用贝叶斯设置中的伯努利分布建模)。sklearn中提供了Binarizer实现二值化,默认阈值为0,也就是将非正数映射为0,将正数映射为1。也可以在实例化时通过参数threshold,设置其他阈值。


X = [[ 1., -1.,  2.], [ 2.,  -4.,  0.], [ 3.,  2., -1.]] binarizer = preprocessing.Binarizer().fit(X) binarizer Binarizer(copy=True, threshold=0.0) binarizer.transform(X) array([[1., 0., 1.], [1., 0., 0.], [1., 1., 0.]]) binarizer = preprocessing.Binarizer(threshold=1.5).fit(X) binarizer.transform(X) array([[0., 0., 1.], [1., 0., 0.], [1., 1., 0.]])(2)分段


二值化只能将数据映射为两个值,分段可以对数据进行排序后分为多个部分然后进行编码。在sklearn中,分段操作通过KBinsDiscretizer类进行。KBinsDiscretizer类有三个重要参数,必须了解一下:

640.png

X = [[-2, 1, -4,   -1],
     [-1, 2, -3, -0.5],
     [ 0, 3, -2,  0.5],
     [ 1, 4, -1,    2]]
est = preprocessing.KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform').fit(X)
est.transform(X)
array([[0., 0., 0., 0.],
       [1., 1., 1., 0.],
       [2., 2., 2., 1.],
       [2., 2., 2., 2.]])
相关文章
|
11天前
|
机器学习/深度学习 数据可视化 数据挖掘
使用Python进行数据分析和可视化
【10月更文挑战第42天】本文将介绍如何使用Python进行数据分析和可视化。我们将从数据导入、清洗、探索性分析、建模预测,以及结果的可视化展示等方面展开讲解。通过这篇文章,你将了解到Python在数据处理和分析中的强大功能,以及如何利用这些工具来提升你的工作效率。
|
20天前
|
机器学习/深度学习 数据采集 数据挖掘
解锁 Python 数据分析新境界:Pandas 与 NumPy 高级技巧深度剖析
Pandas 和 NumPy 是 Python 中不可或缺的数据处理和分析工具。本文通过实际案例深入剖析了 Pandas 的数据清洗、NumPy 的数组运算、结合两者进行数据分析和特征工程,以及 Pandas 的时间序列处理功能。这些高级技巧能够帮助我们更高效、准确地处理和分析数据,为决策提供支持。
38 2
|
25天前
|
机器学习/深度学习 数据采集 算法
Python机器学习:Scikit-learn库的高效使用技巧
【10月更文挑战第28天】Scikit-learn 是 Python 中最受欢迎的机器学习库之一,以其简洁的 API、丰富的算法和良好的文档支持而受到开发者喜爱。本文介绍了 Scikit-learn 的高效使用技巧,包括数据预处理(如使用 Pipeline 和 ColumnTransformer)、模型选择与评估(如交叉验证和 GridSearchCV)以及模型持久化(如使用 joblib)。通过这些技巧,你可以在机器学习项目中事半功倍。
36 3
|
10天前
|
数据采集 数据可视化 数据挖掘
掌握Python数据分析,解锁数据驱动的决策能力
掌握Python数据分析,解锁数据驱动的决策能力
|
18天前
|
并行计算 数据挖掘 大数据
Python数据分析实战:利用Pandas处理大数据集
Python数据分析实战:利用Pandas处理大数据集
|
18天前
|
数据采集 数据可视化 数据挖掘
利用Python进行数据分析:Pandas库实战指南
利用Python进行数据分析:Pandas库实战指南
|
20天前
|
SQL 数据挖掘 Python
数据分析编程:SQL,Python or SPL?
数据分析编程用什么,SQL、python or SPL?话不多说,直接上代码,对比明显,明眼人一看就明了:本案例涵盖五个数据分析任务:1) 计算用户会话次数;2) 球员连续得分分析;3) 连续三天活跃用户数统计;4) 新用户次日留存率计算;5) 股价涨跌幅分析。每个任务基于相应数据表进行处理和计算。
|
20天前
|
数据采集 数据可视化 数据挖掘
使用Python进行数据分析和可视化
【10月更文挑战第33天】本文将介绍如何使用Python编程语言进行数据分析和可视化。我们将从数据清洗开始,然后进行数据探索性分析,最后使用matplotlib和seaborn库进行数据可视化。通过阅读本文,你将学会如何运用Python进行数据处理和可视化展示。
|
4月前
|
数据采集 数据可视化 数据挖掘
数据分析大神养成记:Python+Pandas+Matplotlib助你飞跃!
在数字化时代,数据分析至关重要,而Python凭借其强大的数据处理能力和丰富的库支持,已成为该领域的首选工具。Python作为基石,提供简洁语法和全面功能,适用于从数据预处理到高级分析的各种任务。Pandas库则像是神兵利器,其DataFrame结构让表格型数据的处理变得简单高效,支持数据的增删改查及复杂变换。配合Matplotlib这一数据可视化的魔法棒,能以直观图表展现数据分析结果。掌握这三大神器,你也能成为数据分析领域的高手!
85 2
|
4月前
|
机器学习/深度学习 数据采集 数据可视化
基于爬虫和机器学习的招聘数据分析与可视化系统,python django框架,前端bootstrap,机器学习有八种带有可视化大屏和后台
本文介绍了一个基于Python Django框架和Bootstrap前端技术,集成了机器学习算法和数据可视化的招聘数据分析与可视化系统,该系统通过爬虫技术获取职位信息,并使用多种机器学习模型进行薪资预测、职位匹配和趋势分析,提供了一个直观的可视化大屏和后台管理系统,以优化招聘策略并提升决策质量。
193 4