文章目录
一、sklearn 中的数据集读取
二、sklearn 中的数据集切分方法
三、sklearn 中的数据标准化与归一化
1. 标准化 Standardization
2. 归一化 Normalization
四、尝试使用逻辑回归评估器
五、sklearn 中的构建机器学习流
六、sklearn 的模型保存
- 在对 sklearn 整体情况有了一定的了解之后,接下来我们来介绍 sklearn 中机器学习建模过程常用的一些功能。
# 科学计算模块 import numpy as np import pandas as pd # 绘图模块 import matplotlib as mpl import matplotlib.pyplot as plt # 自定义模块 from ML_basic_function import *
接下来,我们进一步构建功能实现更加完整与复杂的建模过程,并练习使用更多的 sklearn 中的相关功能。
一、sklearn 中的数据集读取
sklearn 提供了非常多的内置数据集,并且还提供了一些创建数据集的方法。
sklearn 中的数据集相关功能都在 datasets 模块下,我们可以通过 API 文档中的 datasets 模块所包含的内容对所有的数据集和创建数据集的方法进行概览。
sklearn 中提供了结构化数据集(如经典的鸢尾花数据集、波士顿房价数据集、乳腺癌数据集等),同时也提供了一些如图片数据、文本数据等数据集,可以使用 load 函数来进行读取。
此外,sklearn 中还提供了许多能够创建不同数据分布的数据生成器(用 make 函数创建),和我们此前定义的数据生成器类似,都是可以用于创建测试评估器性能的数据生成器。
- 首先是鸢尾花数据的读取,我们可借助 load_iris 来进行数据的读取。简单读取方法如下:
from sklearn.datasets import load_iris iris_data = load_iris() # 查看读取结果 iris_data
- 注意,在默认情况下,数据读取结果的类型是Bunch类型,是一个类似字典类型的对象:
type(iris_data) #sklearn.utils.Bunch
而该对象(字典)有如下属性(键值对):
Name | Description |
data | 数据集特征矩阵 |
target | 数据集标签数组 |
feature_names | 各列名称 |
target_names | 各类别名称 |
frame | 当生成对象是DataFrame时,返回完整的DataFrame |
# 返回特征 iris_data.data[:10] #array([[5.1, 3.5, 1.4, 0.2], # [4.9, 3. , 1.4, 0.2], # [4.7, 3.2, 1.3, 0.2], # [4.6, 3.1, 1.5, 0.2], # [5. , 3.6, 1.4, 0.2], # [5.4, 3.9, 1.7, 0.4], # [4.6, 3.4, 1.4, 0.3], # [5. , 3.4, 1.5, 0.2], # [4.4, 2.9, 1.4, 0.2], # [4.9, 3.1, 1.5, 0.1]]) # 返回标签 iris_data.target[:10] #array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) # 返回各列名称 iris_data.feature_names #['sepal length (cm)', # 'sepal width (cm)', # 'petal length (cm)', # 'petal width (cm)'] # 返回标签各类别名称 iris_data.target_names[:10] #array(['setosa', 'versicolor', 'virginica'], dtype='<U10')
- 当然,如果希望只返回特征矩阵和标签数组这两个对象,则可以通过在读取数据集时设置参数 return_X_y 为 True 来实现。
X, y = load_iris(return_X_y=True) X[:10] #array([[5.1, 3.5, 1.4, 0.2], # [4.9, 3. , 1.4, 0.2], # [4.7, 3.2, 1.3, 0.2], # [4.6, 3.1, 1.5, 0.2], # [5. , 3.6, 1.4, 0.2], # [5.4, 3.9, 1.7, 0.4], # [4.6, 3.4, 1.4, 0.3], # [5. , 3.4, 1.5, 0.2], # [4.4, 2.9, 1.4, 0.2], # [4.9, 3.1, 1.5, 0.1]]) y[:10] #array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
- 而如果想创建 DataFrame 对象,则可以通过在读取数据集时设置参数 as_frame 为 True 来实现。
iris_dataFrame = load_iris(as_frame=True) iris_dataFrame.frame
- 更多信息,可以通过查阅 API 或者帮助文档获得。
- 当然不仅鸢尾花数据的读取过程如此,sklearn 中其他数据的读取过程也是类似。
- 接下来,我们借助上述创建的 X 和 y 带入进行后续建模。
二、sklearn 中的数据集切分方法
在 sklearn 中,我们可以通过调用 train_test_split 函数来完成数据集切分,当然数据集切分的目的是为了更好的进行模型性能评估,而更好的进行模型性能评估则是为了更好的进行模型挑选。
因此 train_test_split 函数实际上是在 model_selection 模块下。
from sklearn.model_selection import train_test_split
- 该函数和此前我们定义的数据集切分函数在功能和使用上都基本一致,我们可以直接通过查阅该函数的帮助文档来了解核心信息:
# 查阅该函数的帮助文档 train_test_split?
- 此处有两个地方需要注意,其一是随机数种子的设置,和此前手动定义的数据集切分函数一样,random_state 取值不同,切分结果就会各有不同:
X = np.arange(12).reshape((6, 2)) X #array([[ 0, 1], # [ 2, 3], # [ 4, 5], # [ 6, 7], # [ 8, 9], # [10, 11]]) y = np.array([0, 0, 0, 1, 1, 1]) train_test_split(X, y, random_state=42) #[array([[10, 11], # [ 4, 5], # [ 8, 9], # [ 6, 7]]), # array([[0, 1], # [2, 3]]), # array([1, 0, 1, 1]), # array([0, 0])] train_test_split(X, y, random_state=24) #[array([[2, 3], # [0, 1], # [6, 7], # [4, 5]]), # array([[ 8, 9], # [10, 11]]), # array([0, 0, 1, 0]), # array([1, 1])]
- 而 stratify 参数则是控制训练集和测试集不同类别样本所占比例的参数,若希望切分后的训练集和测试集中 0、1 两类的比例和原始数据相同(1:1),则可另 stratify=y,则有结果如下:
train_test_split(X, y, stratify=y, random_state=42) #[array([[ 2, 3], # [10, 11], # [ 0, 1], # [ 8, 9]]), # array([[6, 7], # [4, 5]]), # array([0, 1, 0, 1]), # array([1, 0])]
- 值得注意的是,此时尽管随机数种子仍然会发挥作用,但由于计算流程发生了变化,最终切分出来的结果将和此前的切分结果不同(但都会保持(1:1)的分布比例)。
train_test_split(X, y, stratify=y, random_state=24) #[array([[ 0, 1], # [10, 11], # [ 8, 9], # [ 2, 3]]), # array([[6, 7], # [4, 5]]), # array([0, 1, 1, 0]), # array([1, 0])]
三、sklearn 中的数据标准化与归一化
- 正如此前介绍的,很多时候我们需要对数据进行归一
在 sklearn 中,则包含了非常多关于数据归一化的函数和评估器,接下来我们对其进行逐一介绍,然后从中挑选合适的函数或者评估器带入进行建模。
从功能上划分,sklearn 中的归一化其实是分为标准化(Standardization)和归一化(Normalization)两类。
其中,此前所介绍的 Z-Score 标准化和 0-1 标准化,都属于 Standardization 的范畴,而在 sklearn 中,Normalization 则特指针对单个样本(一行数据)利用其范数进行放缩的过程。
不过二者都属于数据预处理范畴,都在 sklearn 中的 Preprocessing data 模块下。
from sklearn import preprocessing
from sklearn import preprocessing
需要注意的是,此前我们介绍数据归一化时有讨论过标准化和归一化名称上的区别,在大多数场景下其实我们并不会对其进行特意的区分,但 sklearn 中标准化和归一化则各指代一类数据处理方法,此处需要注意。
1. 标准化 Standardization
sklearn 的标准化过程,即包括 Z-Score 标准化,也包括 0-1 标准化,并且即可以通过实用函数来进行标准化处理,同时也可以利用评估器来执行标准化过程。
接下来我们分不同功能以的不同实现形式来进行讨论:
Z-Score 标准化的函数实现方法
我们可以通过 preprocessing 模块下的 scale 函数进行快速的 Z-Score 标准化处理。
preprocessing.scale?
- 上述函数说明文档并不难懂,接下来我们简单尝试利用该函数进行数据归一化处理。
X = np.arange(9).reshape(3, 3) X #array([[0, 1, 2], # [3, 4, 5], # [6, 7, 8]]) preprocessing.scale(X) #array([[-1.22474487, -1.22474487, -1.22474487], # [ 0. , 0. , 0. ], # [ 1.22474487, 1.22474487, 1.22474487]]) # 对比此前定义的函数处理结果 z_score(X) #array([[-1.22474487, -1.22474487, -1.22474487], # [ 0. , 0. , 0. ], # [ 1.22474487, 1.22474487, 1.22474487]])
Z-Score 标准化的评估器实现方法
实用函数进行标准化处理,尽管从代码实现角度来看清晰易懂,但却不适用于许多实际的机器学习建模场景。
其一是因为在进行数据集的训练集和测试集切分后,我们首先要在训练集进行标准化、然后统计训练集上统计均值和方差再对测试集进行标准化处理,因此其实还需要一个统计训练集相关统计量的过程。
其二则是因为相比实用函数,sklearn 中的评估器其实会有一个非常便捷的串联的功能,sklearn 中提供了 Pipeline 工具能够对多个评估器进行串联进而组成一个机器学习流,从而简化模型在重复调用时候所需代码量,因此通过评估器的方法进行数据标准化,其实是一种更加通用的选择。
既然是实用评估器进行数据标准化,那就需要遵照评估器的一般使用过程:
首先是评估器导入:
from sklearn.preprocessing import StandardScaler
- 然后是查阅评估器参数,然后进行评估器的实例化:
# 查阅参数 StandardScaler? scaler = StandardScaler()
- 然后导入数据,进行训练,此处也是使用 fit 函数进行训练:
X = np.arange(15).reshape(5, 3) X #array([[ 0, 1, 2], # [ 3, 4, 5], # [ 6, 7, 8], # [ 9, 10, 11], # [12, 13, 14]]) X_train, X_test = train_test_split(X) X_train, X_test #(array([[ 9, 10, 11], # [ 6, 7, 8], # [ 0, 1, 2]]), # array([[12, 13, 14], # [ 3, 4, 5]])) scaler.fit(X_train) #StandardScaler()
虽然同样是输入数据,但标准化的评估器和训练模型的评估器实际上是不同的计算过程。
此前我们介绍的线性方程的评估器,输入数据进行训练的过程(fit 过程)实际上是计算线性方程的参数,而此处标准化的评估器的训练结果实际上是对输入数据的相关统计量进行了汇总计算,也就是计算了输入数据的均值、标准差等统计量,后续将用这些统计量对各数据进行标准化计算。
不过无论计算过程是否相同,评估器最终计算结果都可以通过相关属性进行调用和查看:
# 查看训练数据各列的标准差 scaler.scale_ #array([3.74165739, 3.74165739, 3.74165739]) # 查看训练数据各列的均值 scaler.mean_ #array([5., 6., 7.]) # 查看训练数据各列的方差 scaler.var_ #array([14., 14., 14.]) np.sqrt(scaler.var_) #array([3.74165739, 3.74165739, 3.74165739]) # 总共有效的训练数据条数 scaler.n_samples_seen_ #3
- 当然,截止目前,我们只保留了训练数据的统计量,但尚未对任何数据进行修改,输入的训练数据也是如此。
X_train #array([[ 9, 10, 11], # [ 6, 7, 8], # [ 0, 1, 2]])
- 接下来,我们可以通过评估器中的 transform 方法来进行数据标准化处理。
- 注意,算法模型的评估器是利用 predict 方法进行数值预测,而标准化评估器则是利用 transform 方法进行数据的数值转化。
## 利用训练集的均值和方差对训练集进行标准化处理 scaler.transform(X_train) #array([[ 1.06904497, 1.06904497, 1.06904497], # [ 0.26726124, 0.26726124, 0.26726124], # [-1.33630621, -1.33630621, -1.33630621]]) # 利用训练集的均值和方差对测试集进行标准化处理 scaler.transform(X_test) #array([[ 1.87082869, 1.87082869, 1.87082869], # [-0.53452248, -0.53452248, -0.53452248]]) z_score(X_train) #array([[ 1.06904497, 1.06904497, 1.06904497], # [ 0.26726124, 0.26726124, 0.26726124], # [-1.33630621, -1.33630621, -1.33630621]])
- 此外,我们还可以使用 fit_transform 对输入数据进行直接转化:
scaler = StandardScaler() # 一步执行在X_train上fit和transfrom两个操作 scaler.fit_transform(X_train) #array([[ 1.06904497, 1.06904497, 1.06904497], # [ 0.26726124, 0.26726124, 0.26726124], # [-1.33630621, -1.33630621, -1.33630621]]) X_train #array([[ 9, 10, 11], # [ 6, 7, 8], # [ 0, 1, 2]]) scaler.transform(X_test) #array([[ 1.87082869, 1.87082869, 1.87082869], # [-0.53452248, -0.53452248, -0.53452248]])
- 接下来,我们就能直接带入标准化后的数据进行建模了。
- 0-1 标准化的函数实现方法
- 和 Z-Score 标准化类似,0-1 标准化也有函数实现和评估器实现两种,先看 0-1 标准化的函数实现过程:
# 查看函数说明文档 preprocessing.minmax_scale? X #array([[ 0, 1, 2], # [ 3, 4, 5], # [ 6, 7, 8], # [ 9, 10, 11], # [12, 13, 14]]) preprocessing.minmax_scale(X) #array([[0. , 0. , 0. ], # [0.25, 0.25, 0.25], # [0.5 , 0.5 , 0.5 ], # [0.75, 0.75, 0.75], # [1. , 1. , 1. ]]) # 对比自定义函数计算结果 maxmin_norm(X) #array([[0. , 0. , 0. ], # [0.25, 0.25, 0.25], # [0.5 , 0.5 , 0.5 ], # [0.75, 0.75, 0.75], # [1. , 1. , 1. ]])
- 0-1 标准化的评估器实现方法
- 类似的,我们可以调用评估器进行 0-1 标准化。
from sklearn.preprocessing import MinMaxScaler MinMaxScaler? scaler = MinMaxScaler() scaler.fit_transform(X) #array([[0. , 0. , 0. ], # [0.25, 0.25, 0.25], # [0.5 , 0.5 , 0.5 ], # [0.75, 0.75, 0.75], # [1. , 1. , 1. ]]) X #array([[ 0, 1, 2], # [ 3, 4, 5], # [ 6, 7, 8], # [ 9, 10, 11], # [12, 13, 14]]) scaler.data_min_ #array([0., 1., 2.]) scaler.data_max_ #array([12., 13., 14.])
- 此外,sklearn 中还有针对稀疏矩阵的标准化(MaxAbsScaler)、针对存在异常值点特征矩阵的标准化(RobustScaler)、以及非线性变化的标准化(Non-linear transformation)等方法。
2. 归一化 Normalization
标准化不同,sklearn 中的归一化特指将单个样本(一行数据)放缩为单位范数(1范数或者2范数为单位范数)的过程,该操作常见于核方法或者衡量样本之间相似性的过程中。
同样,归一化也有函数实现和评估器实现两种方法。
归一化的函数实现方法
先查看函数相关说明文档:
preprocessing.normalize?
X #array([[ 0, 1, 2], # [ 3, 4, 5], # [ 6, 7, 8], # [ 9, 10, 11], # [12, 13, 14]]) # 1-范数单位化过程 preprocessing.normalize(X, norm='l1') #array([[0. , 0.33333333, 0.66666667], # [0.25 , 0.33333333, 0.41666667], # [0.28571429, 0.33333333, 0.38095238], # [0.3 , 0.33333333, 0.36666667], # [0.30769231, 0.33333333, 0.35897436]]) np.linalg.norm(X, ord=1, axis=1) #array([ 3., 12., 21., 30., 39.]) np.sum(X, axis=1) #array([ 3, 12, 21, 30, 39]) X / np.linalg.norm(X, ord=1, axis=1).reshape(5, 1) #array([[0. , 0.33333333, 0.66666667], # [0.25 , 0.33333333, 0.41666667], # [0.28571429, 0.33333333, 0.38095238], # [0.3 , 0.33333333, 0.36666667], # [0.30769231, 0.33333333, 0.35897436]]) # 2-范数单位化过程 preprocessing.normalize(X, norm='l2') #array([[0. , 0.4472136 , 0.89442719], # [0.42426407, 0.56568542, 0.70710678], # [0.49153915, 0.57346234, 0.65538554], # [0.5178918 , 0.57543534, 0.63297887], # [0.53189065, 0.57621487, 0.62053909]]) np.linalg.norm(X, ord=2, axis=1) #array([ 2.23606798, 7.07106781, 12.20655562, 17.3781472 , 22.56102835]) np.sqrt(np.sum(np.power(X, 2), axis=1)) #array([ 2.23606798, 7.07106781, 12.20655562, 17.3781472 , 22.56102835]) X / np.linalg.norm(X, ord=2, axis=1).reshape(5, 1) #array([[0. , 0.4472136 , 0.89442719], # [0.42426407, 0.56568542, 0.70710678], # [0.49153915, 0.57346234, 0.65538554], # [0.5178918 , 0.57543534, 0.63297887], # [0.53189065, 0.57621487, 0.62053909]]) # 范数单位化结果 np.linalg.norm(preprocessing.normalize(X, norm='l2'), ord=2, axis=1) #array([1., 1., 1., 1., 1.])
- 此外,我们也可以通过调用评估器来实现上述过程:
from sklearn.preprocessing import Normalizer Normalizer? normlize = Normalizer() normlize.fit_transform(X) #array([[0. , 0.4472136 , 0.89442719], # [0.42426407, 0.56568542, 0.70710678], # [0.49153915, 0.57346234, 0.65538554], # [0.5178918 , 0.57543534, 0.63297887], # [0.53189065, 0.57621487, 0.62053909]]) normlize = Normalizer(norm='l1') normlize.fit_transform(X) #array([[0. , 0.33333333, 0.66666667], # [0.25 , 0.33333333, 0.41666667], # [0.28571429, 0.33333333, 0.38095238], # [0.3 , 0.33333333, 0.36666667], # [0.30769231, 0.33333333, 0.35897436]])
值得注意,除了标准化和归一化之外,还有一个正则化(Regularization)的概念。
所谓正则化,往往指的是通过在损失函数上加入参数的 1- 范数或者 2- 范数的过程,该过程能够有效避免模型过拟合。
关于评估器、解释器、转化器等名词的辨析:
其实这一组概念广泛存在于不同的算法库和算法框架中,但不同的算法库对其的定义各有不同,并且 sklearn 对其定义也并不清晰。
因此,为了统一概念
四、尝试使用逻辑回归评估器
- 接下来,我们尝试对上述鸢尾花数据进行逻辑回归模型多分类预测,需要注意的是,sklearn 中的逻辑回归在默认参数下就支持进行多分类问题判别,并且支持此前介绍的 MvM 和 OvR 策略。
- 首先我们先尝试使用逻辑回归评估器进行建模:
# 导入逻辑回归评估器 from sklearn.linear_model import LogisticRegression # 数据准备 X, y = load_iris(return_X_y=True) LogisticRegression? # 实例化模型,使用默认参数 clf_test = LogisticRegression(max_iter=1000, multi_class='multinomial') # 导
此处设置两个参数,一个是最大迭代次数,另一个则是多分类问题时采用 MvM 策略。
如不设置 multi_class 参数,其实默认情况下的 auto 在此时也会选择 multinomial 策略。
该策略也是在模型不受其他约束情况下(如优化方法)时 auto 会默认选择的策略。
# 带入全部数据进行训练 clf_test.fit(X, y) #LogisticRegression(max_iter=1000, multi_class='multinomial') # 查看线性方程系数 clf_test.coef_ #array([[-0.42354204, 0.9673748 , -2.51718519, -1.07940405], # [ 0.5345048 , -0.32156595, -0.20635727, -0.94439435], # [-0.11096276, -0.64580885, 2.72354246, 2.02379841]]) # 在全部数据集上进行预测 clf_test.predict(X)[:10] #array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) # 查看概率预测结果 clf_test.predict_proba(X)[:10] #array([[9.81585264e-01, 1.84147216e-02, 1.44939596e-08], # [9.71339506e-01, 2.86604639e-02, 3.01840948e-08], # [9.85278813e-01, 1.47211746e-02, 1.23337373e-08], # [9.76069526e-01, 2.39304341e-02, 3.96921529e-08], # [9.85236392e-01, 1.47635957e-02, 1.19995412e-08], # [9.70226993e-01, 2.97729326e-02, 7.39546647e-08], # [9.86779074e-01, 1.32209059e-02, 1.99725384e-08], # [9.76150304e-01, 2.38496683e-02, 2.77243996e-08], # [9.79633463e-01, 2.03665062e-02, 3.05952963e-08], # [9.68764573e-01, 3.12353957e-02, 3.17246775e-08]])
上述过程在我们尚未了解逻辑回归评估器细节时、仅仅将其视作一个评估器、并采用评估器通用方法就完成了建模的全过程,足以看出 sklearn 的易用性。
不过需要知道是,sklearn 中的逻辑回归实际上是一个使用方法非常多样的模型。
接下来,我们对模型预测结果进行准确率计算,首先我们可以直接调用评估器的 score 方法来进行准确率的查看:
clf_test.score(X, y) #0.9733333333333334
五、sklearn 中的构建机器学习流
所谓机器学习流,其实就指的是将多个机器学习的步骤串联在一起,形成一个完整的模型训练流程。
在 sklearn 中,我们可以借助其 make_pipline 类的相关功能来实现。
这里需要注意的是,sklearn 中只能将评估器类进行串联形成机器学习流,而不能串联实用函数,并且最终串联的结果其实也等价于一个评估器。
当然,这也从侧面说明 sklearn 评估器内部接口的一致性。
接下来,我们就利用 sklearn 中构建机器学习流的方法将上述数据归一化、逻辑回归进行多分类建模等过程串联在一起,并提前进行数据切分,即执行一个更加完整的机器学习建模流程。
from sklearn.pipeline import make_pipeline make_pipeline?
接下来,可以通过如下方式将模型类进行机器学习流的集成。
需要注意的是,只有模型类才能参与构建机器学习流,而实用函数不行。
# 在make_pipeline中输入评估器的过程同时对评估器类进行参数设置 pipe = make_pipeline(StandardScaler(),LogisticRegression(max_iter=1000))
- 然后进行数据集切分。
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
接下来,我们将 pipe 对象看成是一个完整的模型类(一个可以先执行 Z-Score 标准化再进行逻辑回归建模的模型),直接使用 fit 对其进行训练:
pipe.fit(X_train, y_train) #Pipeline(steps=[('standardscaler', StandardScaler()), # ('logisticregression', LogisticRegression(max_iter=1000))])
该过程就相当于两个评估器都进行了训练,然后我们即可使用 predict 方法,利用 pipe 对数据集进行预测,当然实际过程是先(借助训练数据的统计量)进行归一化,然后再进行逻辑回归模型预测。
pipe.predict(X_test) #array([1, 0, 2, 1, 1, 0, 1, 2, 1, 1, 2, 0, 0, 0, 0, 1, 2, 1, 1, 2, 0, 2, # 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 0, 0, 2, 1, 0]) pipe.score(X_test, y_test) #1.0 pipe.score(X_train, y_train) #0.9642857142857143
六、sklearn 的模型保存
- 当模型构建完毕之后,我们即可借助 joblib 包来进行 sklearn 的模型存储和读取,相关功能非常简单,我们可以使用 dump 函数进行模型保存,使用 load 函数进行模型读取:
import joblib joblib.dump? joblib.dump(pipe,'pipe.model') #['pipe.model'] pipe1 = joblib.load('pipe.model') pipe1.score(X_train, y_train) #0.9642857142857143
以上就是关于 sklearn 建模的常用功能,基于这些功能,在下一小节开始,我们将从逻辑回归出发,讨论关于正则化、过拟合、特征衍生、特征筛选等非常重要的机器学习相关概念