乐趣区

关于机器学习:机器学习实战-SKLearn最全应用指南

作者:韩信子 @ShowMeAI
教程地址:http://www.showmeai.tech/tutorials/41
本文地址:http://www.showmeai.tech/article-detail/203
申明:版权所有,转载请分割平台与作者并注明出处
珍藏 ShowMeAI 查看更多精彩内容

引言

咱们在上一篇 SKLearn 入门与简略利用案例 里给大家讲到了 SKLearn 工具的根本板块与应用办法,在本篇内容中,咱们开展解说 SKLearn 的进阶与核心内容。SKLearn 中有六大工作模块,如下图所示:别离是分类、回归、聚类、降维、模型抉择和预处理。

  • SKLearn 官网:https://scikit-learn.org/stable/
  • SKLearn 的疾速应用办法也举荐大家查看 ShowMeAI 的文章和速查手册 AI 建模工具速查 |Scikit-learn 使用指南

在 SKLearn 中,因为做了下层的封装,分类模型、回归模型、聚类与降维模型、预处理器等等都叫做预计器(estimator),就像在 Python 里「万物皆对象」,在 SKLearn 里「万物皆预计器」。

在本篇内容中,咱们将给大家进一步深刻解说 scikit-learn 工具库的应用办法,力求残缺笼罩 sklearn 工具库利用的方方面面。本文的内容板块包含:

  • 机器学习基础知识:机器学习定义与四因素:数据、工作、性能度量和模型。机器学习概念,以便和 SKLearn 对应匹配上。
  • SKLearn 解说:API 设计原理,sklearn 几大特点:一致性、可测验、规范类、可组合和默认值,以及 SKLearn 自带数据以及贮存格局。
  • SKLearn 三大外围 API 解说:包含预计器、预测器和转换器。这个板块很重要,大家理论利用时次要是借助于外围 API 落地。
  • SKLearn 高级 API 解说 :包含简化代码量的流水线(Pipeline 预计器),集成模型(Ensemble 预计器)、有多类别 - 多标签 - 多输入分类模型(Multiclass 和 Multioutput 预计器) 和模型抉择工具(Model Selection 预计器)。

1. 机器学习简介

对于本节内容,强烈推荐大家浏览 ShowMeAI 文章 图解机器学习 | 机器学习基础知识 图解机器学习 | 模型评估办法与准则,ShowMeAI 对相干常识内容开展做了具体解说。

1.1 定义和形成元素

何为机器学习?巨匠汤姆米切尔(Tom Mitchell)对机器学习定义的原话是:

A computer program is said to learn from experience E with respect to some class of tasks T and performance measure P if its performance at tasks in T, as measured by P, improves with experience E.

这段英文中有两个词 computer program 和 learn,翻译成中文就是机器 (计算机程序) 和学习,整体翻译下来就是说:如果计算机程序在 T 工作上的性能 (由 P 掂量) 随着教训 E 而进步,则称计算机程序从教训 E 中学习某类工作 T。

由上述机器学习的定义可知机器学习蕴含四个元素:

  • 数据(Data)
  • 工作(Task)
  • 性能度量(Quality Metric)
  • 算法(Algorithm)

1.2 数据

数据 (data) 是信息的载体。数据能够有以下划分形式:

  • 从「数据具体类型」维度划分:结构化数据和非结构化数据。

    • 结构化数据 (structured data) 是由二维表构造来逻辑表白和实现的数据。
    • 非结构化数据是没有预约义的数据,不便用数据库二维表来体现的数据。非结构化数据包含图片,文字,语音和视频等。
  • 从「数据表达形式」维度划分:原始数据和加工数据。
  • 从「数据统计性质」维度划分:样本内数据和样本外数据。

对于非构造数据,通常神经网络有更好的成果,能够参考 ShowMeAI 的文章 [Python 机器学习算法实际]() 中的图像建模例子。

机器学习模型很多时候应用的是结构化数据,即二维的数据表。咱们这里以 iris 花瓣数据集举例,如下图。

上面术语大家在深刻理解机器学习前肯定要弄清楚:

  • 每行的记录 (这是一朵鸢尾花的数据统计),称为一个「 样本(sample)」。
  • 反映样本在某方面的性质,例如萼片长度 (Sepal Length)、花瓣长度(Petal Length),称为「 特色(feature)」。
  • 特色上的取值,例如「样本 1」对应的 5.1、3.5 称为「特征值(feature value)」。
  • 对于样本后果的信息,例如 Setosa、Versicolor,称为「类别标签(class label)」。
  • 蕴含标签信息的示例,则称为「样例 (instance)」,即 样例 =(特色, 标签)
  • 从数据中学得模型的过程称为「学习 (learning)」或「 训练(training)」。
  • 在训练数据中,每个样例称为「训练样例 (training instance)」,整个汇合称为「 训练集(training set)」。

1.3 工作

依据学习的工作模式(训练数据是否有标签),机器学习可分为几大类:

  • 监督学习(有标签)
  • 无监督学习(无标签)
  • 半监督学习(有局部标签)
  • 强化学习(有提早的标签)

下图画出机器学习各类之间的关系。

1.4 性能度量

回归和分类工作中最常见的误差函数以及一些有用的性能度量如下,具体内容能够参考 ShowMeAI 文章 机器学习评估与度量准则

2. SKLearn 数据

SKLearn 作为通用机器学习建模的工具包,蕴含六个工作模块和一个数据导入模块:

  • 监督学习:分类工作
  • 监督学习:回归工作
  • 无监督学习:聚类工作
  • 无监督学习:降维工作
  • 模型抉择工作
  • 数据预处理工作
  • 数据导入模块

首先看看 SKLearn 默认数据格式和自带数据集。

2.1 SKLearn 默认数据格式

Sklean 里模型能间接应用的数据有两种模式:

  • Numpy 二维数组 (ndarray) 的浓密数据(dense data),通常都是这种格局。
  • SciPy 矩阵 (scipy.sparse.matrix) 的稠密数据 (sparse data),比方文本剖析每个单词(字典有 100000 个词) 做独热编码失去矩阵有很多 0,这时用 ndarray 就不适合了,太耗内存。

2.2 自带数据集

SKLearn 外面有很多自带数据集供用户应用。

比方在之前文章 Python 机器学习算法实际 中用到的鸢尾花数据集,蕴含四个特色 (萼片长 / 宽和花瓣长 / 宽) 和三个类别。

咱们能够间接从 SKLearn 外面的 datasets 模块中引入,代码如下(代码能够在 线上 Jupyter 环境 中运行):

# 导入工具库
from sklearn.datasets import load_iris    
iris = load_iris()

#数据是以「字典」格局存储的,看看 iris 的键有哪些。iris.keys()

输入如下:

dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names', 'filename'])

读取数据集的信息:

# 输入 iris 数据中特色的大小、名称等信息和前五个样本。n_samples, n_features = iris.data.shape    
print((n_samples, n_features))    
print(iris.feature_names)    
print(iris.target.shape)    
print(iris.target_names)
iris.data[0:5]

输入如下:

(150, 4)
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
(150,)
['setosa' 'versicolor' 'virginica']
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]])

构建 Dataframe 格局的数据集:

# 将 X 和 y 合并为 Dataframe 格局数据 
import pandas as pd
import seaborn as sns
iris_data = pd.DataFrame( iris.data,     
                          columns=iris.feature_names )    
iris_data['species'] = iris.target_names[iris.target]    
iris_data.head(3).append(iris_data.tail(3))

输入如下:

sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
147 6.5 3.0 5.2 2.0 virginica
148 6.2 3.4 5.4 2.3 virginica
149 5.9 3.0 5.1 1.8 virginica

咱们应用 seaborn 来做一些数据分析,查看一下数据的散布个性。这里应用到的是成对维度的关联剖析,对于 seaborn 的应用办法能够参阅 ShowMeAI 的文章 seaborn 工具与数据可视化教程

# 应用 Seaborn 的 pairplot 查看两两特色之间的关系
sns.pairplot(iris_data, hue='species', palette='husl')

2.3 数据集引入形式

后面提到的是鸢尾花 iris 数据集,咱们通过 load_iris 加载进来,实际上 SKLearn 有三种引入数据模式。

  • 打包好的数据:对于小数据集,用sklearn.datasets.load_*
  • 分流下载数据:对于大数据集,用sklearn.datasets.fetch_*
  • 随机创立数据:为了疾速展现,用sklearn.datasets.make_*

下面这个星号 * 指代具体文件名,如果大家在 Jupyter 这种 IDE 环境中,能够通过 tab 制表符主动补全和抉择。

  • datasets.load_<TAB>
  • datasets.fetch_<TAB>
  • datasets.make_<TAB>

比方咱们调用load_iris

from sklearn import datasets
datasets.load_iris

输入如下:

<function sklearn.datasets.base.load_iris(return_X_y=False)>

咱们调用 load_digits 加载手写数字图像数据集

digits = datasets.load_digits()
digits.keys()

输入:

dict_keys(['data', 'target', 'target_names', 'images', 'DESCR'])

咱们再来看看通过 fetch 拉取数据的示例:

# 加州屋宇数据集
california_housing = datasets.fetch_california_housing()    
california_housing.keys()

输入:

dict_keys(['data', 'target', 'feature_names', 'DESCR'])

3.SKLearn 外围 API

咱们后面提到 SKLearn 里万物皆预计器。预计器是个十分形象的叫法,不谨严的一个了解,咱们能够视其为一个模型(用来回归、分类、聚类、降维),或一套流程(预处理、网格搜寻穿插验证)。

本节三大 API 其实都是预计器:

  • 预计器 (estimator) 通常是用于拟合性能的预计器。
  • 预测器 (predictor) 是具备预测性能的预计器。
  • 转换器 (transformer) 是具备转换性能的预计器。

3.1 预计器

任何能够基于数据集对一些参数进行预计的对象都被称为预计器,它有两个外围点:

  • ① 须要输出数据。
  • ② 能够预计参数。

预计器首先被创立,而后被拟合。

  • 创立预计器:须要设置一组超参数,比方

    • 线性回归里超参数normalize=True
    • K 均值里超参数n_clusters=5
  • 拟合预计器:须要训练集

    • 在监督学习中的代码范式为model.fit(X_train, y_train)
    • 在无监督学习中的代码范式为model.fit(X_train)

拟合之后能够拜访 model 里学到的参数,比方线性回归里的特色系数 coef,或 K 均值里聚类标签 labels,如下(具体的能够在 SKLearn 文档的每个模型页查到)。

  • model.coef_
  • model.labels_

上面看看监督学习的「线性回归」和无监督学习的「 K 均值聚类」的具体例子。

(1) 线性回归

首先从 SKLearn 工具库的 linear_model 中引入 LinearRegression;创立模型对象命名为 model,设置超参数normalizeTrue(在每个特征值上做标准化,这样能保障拟合的稳定性,减速模型拟合速度)。

from sklearn.linear_model import LinearRegression
model = LinearRegression(normalize=True)
model

输入:

LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=True)

创立完后的预计器会显示所有的超参数(比方方才设置的normalize=True),未设置的超参数都应用默认值。

本人创立一个简略数据集(一条直线上的数据点),简略解说一下预计器外面的特色。

import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)    
y = 2 * x + 1    
plt.plot(x, y, 'o')

在咱们生成的数据里,X 是一维,咱们做一点小小的调整,用 np.newaxis 加一个维度,把 [1,2,3] 转成 [[1],[2],[3]],这样的数据状态能够合乎 sklearn 的要求。接着把 X 和 y 送入fit() 函数来拟合线性模型的参数。

X = x[:, np.newaxis]    
model.fit(X, y)

输入为:

LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=True)

拟合完后的预计器和创立完仿佛没有差异,但咱们曾经能够用 model.param_ 拜访到拟合完数据的参数了,如下代码。

print(model.coef_)    
print(model.intercept_)
# 输入后果
# [2.]
# 0.9999999999999982

(2) K 均值

咱们来看看 聚类 的例子,先从 SKLearn 的 cluster 中导入 KMeans,初始化模型对象命名为 model,设置超参数n_cluster 为 3(为了展现不便而咱们晓得用的 iris 数据集有 3 类,实际上能够设置不同数量的n_cluster)。

尽管 iris 数据里蕴含标签 y,但在无监督的聚类中咱们不会应用到这个信息。

from sklearn.cluster import KMeans    
model = KMeans(n_clusters=3)    
model

输入为:

KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
       n_clusters=3, n_init=10, n_jobs=None, precompute_distances='auto',
       random_state=None, tol=0.0001, verbose=0)

iris 数据集蕴含四维特色 (萼片长、萼片宽、花瓣长、花瓣宽),在上面的例子中咱们心愿可视化,这里咱们简略选取两个特色(萼片长、萼片宽) 来做聚类并且可视化后果。

留神上面代码 X = iris.data[:,0:2] 其实就是提取特色维度。

from sklearn.datasets import load_iris    
iris = load_iris()
X = iris.data[:,0:2]    
model.fit(X)

输入为:

KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
       n_clusters=3, n_init=10, n_jobs=None, precompute_distances='auto',
       random_state=None, tol=0.0001, verbose=0)

拟合完后的预计器和创立完仿佛没有差异,但咱们曾经能够用 model.param_ 拜访到拟合完数据的参数了,如下代码。

print(model.cluster_centers_, '\n')    
print(model.labels_, '\n')    
print(model.inertia_, '\n')    
print(iris.target)
[[5.77358491 2.69245283]
 [6.81276596 3.07446809]
 [5.006      3.428]] 

[2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 0 1 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
 1 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 1 0 1 1 1 1
 1 1 0 0 1 1 1 1 0 1 0 1 0 1 1 0 0 1 1 1 1 1 0 0 1 1 1 0 1 1 1 0 1 1 1 0 1
 1 0] 

37.05070212765958 

[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]

这里解释一下 KMeans 模型这几个参数:

  • model.clustercenters:簇核心。三个簇意味着有三个坐标。
  • model.labels_:聚类后的标签。
  • model.inertia_:所有点到对应的簇核心的间隔平方和(越小越好)

小结

尽管下面以有监督学习的 Linear Regression 和无监督学习的 KMeans 举例,但实际上你能够将它们替换成其余别的模型,比方监督学习的 Logistic Regression 和无监督学习的 DBSCAN。它们都是「预计器」,因而都有 fit() 办法。

应用它们的通用伪代码如下:

# 有监督学习
from sklearn.xxx import SomeModel
# xxx 能够是 linear_model 或 ensemble 等
model = SomeModel(hyperparameter)
model.fit(X, y)

# 无监督学习
from sklearn.xxx import SomeModel
# xxx 能够是 cluster 或 decomposition 等
model = SomeModel(hyperparameter)
model.fit(X)

3.2 预测器

预测器是预计器做的一个延展,具备对数据进行预测的性能。

预测器最常见的是 predict() 函数:

  • model.predict(X_test):评估模型在新数据上的体现。
  • model.predict(X_train):确认模型在老数据上的体现。

为了进行新数据评估,咱们先将数据分成 80:20 的训练集 (X_train, y_train) 和测试集 (X_test, y_test),再用从训练集上拟合 fit() 的模型在测试集上预测predict()

from sklearn.datasets import load_iris    
iris = load_iris()
from sklearn.model_selection import train_test_split    
X_train, X_test, y_train, y_test = train_test_split(iris['data'],     
                    iris['target'],     
                    test_size=0.2 )    
print('The size of X_train is', X_train.shape)    
print('The size of y_train is', y_train.shape)    
print('The size of X_test is', X_test.shape)    
print('The size of y_test is', y_test.shape)
The size of X_train is  (120, 4)
The size of y_train is  (120,)
The size of X_test is  (30, 4)
The size of y_test is  (30,)

predict & predict_proba

对于分类问题,咱们不仅想晓得预测的类别是什么,有时咱们还心愿获取预测概率等信息。前者用 predict(),后者用predict_proba()

y_pred = model.predict(X_test)
p_pred = model.predict_proba(X_test)
print(y_test, '\n')
print(y_pred, '\n')
print(p_pred)

score & decision_function

预测器里还有额定的两个函数能够应用。在分类问题中:

  • score()返回的是分类准确率。
  • decision_function()返回的是每个样例在每个类下的分数值。
print(model.score( X_test, y_test) )
print(np.sum(y_pred==y_test)/len(y_test) )
decision_score = model.decision_function(X_test)
print(decision_score)

小结

预计器都有 fit() 办法,预测器都有 predict()score()办法,话中有话不是每个预测器都有 predict_proba()decision_function()办法,这个在用的时候查查官网文档就分明了 (比方RandomForestClassifier 就没有 decision_function() 办法)。

应用它们的通用伪代码如下:

# 有监督学习
from sklearn.xxx import SomeModel
# xxx 能够是 linear_model 或 ensemble 等
model = SomeModel(hyperparameter)
model.fit(X, y)
y_pred = model.predict(X_new)
s = model.score(X_new)

# 无监督学习
from sklearn.xxx import SomeModel
# xxx 能够是 cluster 或 decomposition 等
model = SomeModel(hyperparameter)
model.fit(X)
idx_pred = model.predict(X_new)
s = model.score(X_new)

3.3 转换器

转换器是一种预计器,也有拟合性能,比照预测器做完拟合来预测,转换器做完拟合来转换。外围点如下:

  • 预计器里fit + predict
  • 转换器里fit + transform

本节介绍两大类转换器:

  • 将类别型变量 (categorical) 编码成数值型变量(numerical)
  • 规范化 (normalize) 或标准化 (standardize) 数值型变量

(1) 类别型变量编码

① LabelEncoder&OrdinalEncoder

LabelEncoder 和 OrdinalEncoder 都能够将字符转成数字,然而:

  • LabelEncoder 的输出是一维,比方 1d ndarray
  • OrdinalEncoder 的输出是二维,比方 DataFrame
# 首先给出要编码的列表 enc 和要解码的列表 dec。enc = ['red','blue','yellow','red']    
dec = ['blue','blue','red']

# 从 sklearn 下的 preprocessing 中引入 LabelEncoder,再创立转换器起名 LE,不须要设置任何超参数。from sklearn.preprocessing import LabelEncoder    
LE = LabelEncoder()    
print(LE.fit(enc))    
print(LE.classes_)    
print(LE.transform(dec) )
LabelEncoder()
['blue' 'yellow' 'red']
[0 1 2]

除了 LabelEncoder,OrdinalEncoder 也能够实现编码。如下代码所示:

from sklearn.preprocessing import OrdinalEncoder    
OE = OrdinalEncoder()    
enc_DF = pd.DataFrame(enc)    
dec_DF = pd.DataFrame(dec)    
print(OE.fit(enc_DF) )    
print(OE.categories_)    
print(OE.transform(dec_DF) )
OrdinalEncoder(categories='auto', dtype=<class 'numpy.float64'>)
[array(['blue', 'yellow', 'red'], dtype=object)]
[[0.]
 [1.]
 [2.]]

下面这种编码的问题是,在编码过后会带来不同类别的大小关系,比方这里 3 种颜色其实实质上是平等的,没有大小关系。

咱们的另外一种类别型数据编码形式,独热向量编码 (one-hot encoding) 能够解决这个问题,大家持续往下看。

② OneHotEncoder

独热向量编码其实就是把一个整数用向量的模式体现。上图右侧就是对色彩做独热向量编码。转换器 OneHotEncoder 能够承受两种类型的输出:

  • ① 用 LabelEncoder 编码好的一维数组
  • ② DataFrame

一、用 LabelEncoder 编码好的一维数组 (元素为整数),重塑(用 reshape(-1,1)) 成二维数组作为 OneHotEncoder 输出

from sklearn.preprocessing import OneHotEncoder    
OHE = OneHotEncoder()    
num = LE.fit_transform(enc)    
print(num)    
OHE_y = OHE.fit_transform(num.reshape(-1,1) )    
OHE_y
[2 0 1 2]

输入为:

<4x3 sparse matrix of type '<class'numpy.float64'>'
    with 4 stored elements in Compressed Sparse Row format>

下面后果解释如下:

  • 第 3 行打印出编码后果[2 0 1 2]。
  • 第 5 即将其转成独热模式,输入是一个「稠密矩阵」模式,因为实操中通常类别很多,因而就一步到位用稠密矩阵来节俭内存。

想看该矩阵里具体内容,用 toarray() 函数。

OHE_y.toarray()

输入为:

array([[0., 0., 1.],
       [1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

二、用 DataFrame 作为 OneHotEncoder 输出

OHE = OneHotEncoder()    
OHE.fit_transform(enc_DF).toarray()

输入为:

array([[0., 0., 1.],
       [1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

(2) 特色缩放

数据要做的最重要的转换之一是特色缩放(feature scaling)。相似逻辑回归,神经网络这种计算型模型,对于不同特色的幅度大小差别是敏感的。

具体来说,对于某个特色,咱们有两种变换办法:

  • 标准化(standardization):每个维度的特色减去该特色均值,除以该维度的标准差。
  • 规范化(normalization):每个维度的特色减去该特色最小值,除以该特色的最大值与最小值之差。

① MinMaxScaler

如上图所示,MinMaxScaler 会依据特色的最大最小取值,对数据进行幅度缩放。

from sklearn.preprocessing import MinMaxScaler    
X = np.array([0, 0.5, 1, 1.5, 2, 100] )    
X_scale = MinMaxScaler().fit_transform( X.reshape(-1,1) )    
X_scale

输入为:

array([[0.],
       [0.005],
       [0.01],
       [0.015],
       [0.02],
       [1.]])

② StandardScaler

StandardScaler 做的事件是调整数据分布,尽量靠近正态分布。

from sklearn.preprocessing import StandardScaler    
X_scale = StandardScaler().fit_transform( X.reshape(-1,1) )    
X_scale

输入为:

array([[-0.47424487],
       [-0.46069502],
       [-0.44714517],
       [-0.43359531],
       [-0.42004546],
       [2.23572584]])

留神:fit()函数只能作用在训练集上,如果心愿对测试集变换,只有用训练集上 fit 好的转换器去 transform 即可。不能在测试集上 fit 再 transform,否则训练集和测试集的变换规定不统一,模型学习到的信息就有效了。

4. 高级 API

咱们在这节中给大家介绍 SKLearn 的「高级 API」,即五大元预计器(集成性能的 Ensemble,多分类和多标签的 Multiclass,多输入的 Multioutput,抉择模型的 Model Selection,流水线的 Pipeline)。

  • ensemble.BaggingClassifier
  • ensemble.VotingClassifier
  • multiclass.OneVsOneClassifier
  • multiclass.OneVsRestClassifier
  • multioutput.MultiOutputClassifier
  • model_selection.GridSearchCV
  • model_selection.RandomizedSearchCV
  • pipeline.Pipeline

4.1 Ensemble 预计器

如上图:分类器统计每个子分类器的预测类别数,再用「少数投票」准则失去最终预测。回归器计算每个子回归器的预测平均值。

最罕用的 Ensemble 预计器排列如下:

  • AdaBoostClassifier:逐渐晋升分类器
  • AdaBoostRegressor:逐渐晋升回归器
  • BaggingClassifier:Bagging 分类器
  • BaggingRegressor:Bagging 回归器
  • GradientBoostingClassifier:梯度晋升分类器
  • GradientBoostingRegressor:梯度晋升回归器
  • RandomForestClassifier:随机森林分类器
  • RandomForestRegressor:随机森林回归器
  • VotingClassifier:投票分类器
  • VotingRegressor:投票回归器

咱们用鸢尾花数据 iris,拿以下 estimator 来举例:

  • 含同质预计器RandomForestClassifier
  • 含异质预计器VotingClassifier

首先将数据分成 80:20 的训练集和测试集,并引入 metrics 来计算各种性能指标。

from sklearn.datasets import load_iris    
iris = load_iris()
from sklearn.model_selection import train_test_split    
from sklearn import metrics    
X_train, X_test, y_train, y_test = train_test_split(iris['data'], iris['target'], test_size=0.2)

(1) RandomForestClassifier

随机森林 RandomForestClassifier 通过管制n_estimators 超参数来决定基预计器的个数,在这里是 4 棵决策树(森林由树组成);此外每棵树的最大树深为 5(max_depth=5)。

from sklearn.ensemble import RandomForestClassifier    
RF = RandomForestClassifier(n_estimators=4, max_depth=5)    
RF.fit(X_train, y_train)

输入为:

RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
                       max_depth=5, max_features='auto', max_leaf_nodes=None,
                       min_impurity_decrease=0.0, min_impurity_split=None,
                       min_samples_leaf=1, min_samples_split=2,
                       min_weight_fraction_leaf=0.0, n_estimators=4,
                       n_jobs=None, oob_score=False, random_state=None,
                       verbose=0, warm_start=False)

元预计器和预估器一样也有fit()。上面看看随机森林里蕴含的预计器个数和其自身。

print(RF.n_estimators)    
RF.estimators_

输入为:

4

[DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=5,
                        max_features='auto', max_leaf_nodes=None,
                        min_impurity_decrease=0.0, min_impurity_split=None,
                        min_samples_leaf=1, min_samples_split=2,
                        min_weight_fraction_leaf=0.0, presort=False,
                        random_state=705712365, splitter='best'),
 DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=5,
                        max_features='auto', max_leaf_nodes=None,
                        min_impurity_decrease=0.0, min_impurity_split=None,
                        min_samples_leaf=1, min_samples_split=2,
                        min_weight_fraction_leaf=0.0, presort=False,
                        random_state=1026568399, splitter='best'),
 DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=5,
                        max_features='auto', max_leaf_nodes=None,
                        min_impurity_decrease=0.0, min_impurity_split=None,
                        min_samples_leaf=1, min_samples_split=2,
                        min_weight_fraction_leaf=0.0, presort=False,
                        random_state=1987322366, splitter='best'),
 DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=5,
                        max_features='auto', max_leaf_nodes=None,
                        min_impurity_decrease=0.0, min_impurity_split=None,
                        min_samples_leaf=1, min_samples_split=2,
                        min_weight_fraction_leaf=0.0, presort=False,
                        random_state=1210538094, splitter='best')]

拟合 RF 完再做预测,用 metrics 外面的 accuracy_score 来计算准确率。训练准确率 98.33%,测试准确率 100%。

print ("RF - Accuracy (Train):  %.4g" %     
        metrics.accuracy_score(y_train, RF.predict(X_train)) )    
print ("RF - Accuracy (Test):  %.4g" %     
        metrics.accuracy_score(y_test, RF.predict(X_test)) )
RF - Accuracy (Train):  1
RF - Accuracy (Test):  0.9667

(2) VotingClassifier

随机森林 由同质分类器「决策树」不同,投票分类器由若干个异质分类器组成。上面咱们用 VotingClassifier 建设个含有逻辑回归 (Logistic regression)、随机森林(RandomForest) 和高斯奢侈贝叶斯 (GNB) 三个分类器的集成模型。

RandomForestClassifier 的基分类器只能是决策树,因而只用通过管制 n_estimators 超参数来决定树的个数,而 VotingClassifier 的基分类器要输出每个异质分类器。

from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier

LR = LogisticRegression(solver='lbfgs', multi_class='multinomial')
RF = RandomForestClassifier(n_estimators=5)
GNB = GaussianNB()

Ensemble = VotingClassifier(estimators=[('lr', LR), (‘rf', RF), ('gnb', GNB)], voting='hard' )

Ensemble. fit(X_train, y_train)

后果如下:

VotingClassifier(estimators=[('lr', LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,intercept_scaling=1, max_iter=100, multi_class='multinomial',n_jobs=None, penalty='12', random_state=None, solver='lbfgs',tol=0.0001, verbose=6, warm_start=False)), ('rf', ...e, verbose=0,warm_start=False)), ('gnb', GaussianNB(priors=None, var_smoothing=1e-09))],flatten_transform=None, n_jobs=None, voting='hard', weights=None)

看看 Ensemble 集成模型里蕴含的预计器个数和其自身。

print(len(Ensemble.estimators_) )        
Ensemble.estimators_

后果如下:

3

[LogisticRegression(C=1.0, class_weight-None, dual-False, fit_intercept=True,intercept_scaling=1, max_iter=100, multi_class='multinomial',n_jobs-None, penalty="12", random_state-None, solver='1bfgs',t01=0.0001, verbose=0, warm_start=False),

RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',max_depth=None, max_features='auto', max_leaf_nodes=None,min_impurity_decrease-0.0, min_impurity_splitmin_samples_leaf=1, min_samples_split=2,min_weight_fraction_leaf=0.0, n_estimator:oob_score=False, random_state-None, verbose=
warm_start=False),

GaussianNB(priors-None, var_smoothing=1e-9)]

比照元预计器和它三个组成元素的体现,下过体现如下:

# 拟合
LR.fit(X_train, y_train)        
RF.fit(X_train, y_train)        
GNB.fit(X_train, y_train)
# 评估成果
print ("LR - Accuracy (Train): %.4g" % metrics.accuracy_score(y_train, LR.predict(X_train)) )
print ("RF - Accuracy (Train): %.4g" % metrics.accuracy_score(y_train, RF.predict(X_train)) )
print ("GNB - Accuracy (Train): %.4g" % metrics.accuracy_score(y_train, GNB.predict(X_train)) )
print ("Ensemble - Accuracy (Train): %.4g" % metrics.accuracy_score(y_train, Ensemble.predict(X_train)) )
print ("LR - Accuracy (Test): %.4g" % metrics.accuracy_score(y_test, LR.predict(X_test)) )

print ("RF - Accuracy (Test): %.4g" % metrics.accuracy_score(y_test, RF.predict(x_test)) )
print ("GNB - Accuracy (Test): %.4g" % metrics.accuracy_score(y_test, RF.predict(X_test)) )
print ("Ensemble - Accuracy (Test): %.4g" % metrics.accuracy_score(y test, Ensemble.predict(X_test)) )
# 运行后果
LR - Accuracy (Train): 0.975
RF - Accuracy (Train): 0.9833
GNB - Accuracy (Train): 0.95
Ensemble - Accuracy (Train): 0.9833 
LR - Accuracy (Test): 1
RF - Accuracy (Test): 1
GNB - Accuracy (Test): 1
Ensemble - Accuracy (Test): 1

4.2 Multiclass 预计器

sklearn.multiclass能够解决多类别(multi-class) 的多标签(multi-label) 的分类问题。上面咱们会应用数字数据集 digits 作为示例数据来解说。咱们先将数据分成 80:20 的训练集和测试集。

# 导入数据
from sklearn.datasets import load_digits                 
digits = load_digits()        
digits.keys()

输入如下:

# 输入后果
dict_keys(['data', 'target', 'target_names','images', 'DESCR'])

上面咱们切分数据集:

# 数据集切分
X_train, X_test, y_train, y_test = train_test_split(digits['data'], digits['target'], test_size=0.2 )
                
print('The size of X_train is', X_train.shape)        
print('The size of y_train is', y_train.shape)        
print('The size of X_test is', X_test.shape)        
print('The size of y_test is', y_test.shape)

输入如下

The size of X_train is (1437, 64)
The size of y_train is (1437,)
The size of X_test is (360, 64)
The size of y_test is (360,)

训练集和测试集别离有 1437 和 360 张图像。每张照片是蕴含 8×8 的像素,咱们用 flatten 操作把 2 维的 8×8 展平为 1 维的 64。

看看训练集中前 100 张图片和对应的标签(如下图)。像素很低,但基本上还是能看清。

fig, axes = plt.subplots(10, 16, figsize=(8, 8) )
fig.subplots_adjust(hspace=0.1, wspace=0.1)
for i, ax in enumerate(axes.flat):
    ax.imshow(X_train[i,:].reshape(8,8), cmap='binary’, interpolation='nearest’)
    ax.text(0.05, 0.05, str(y_train[i]),
    transform=ax.transAxes, color='blue')
    ax.set_xticks([])
    ax.set_yticks([])

(1) 多类别分类

手写数字有 0 - 9 十类,但手头上只有二分类预计器(比方像撑持向量机)怎么用呢?咱们能够采取以下策略解决:

  • 一对一(One vs One,OvO):一个分类器用来解决数字 0 和数字 1,一个用来解决数字 0 和数字 2,一个用来解决数字 1 和 2,以此类推。N 个类须要 N(N-1)/ 2 个分类器。
  • 一对其余(One vs All,OvA):训练 10 个二分类器,每一个对应一个数字,第一个分类「1」和「非 1」,第二个分类「2」和「非 2」,以此类推。N 个类须要 N 个分类器。

① OneVsOneClassifier

思考一个具体天气多分类问题,天气能够是晴天、阴天和雨天,在 OvO 中,三个分类器为 f1、f2 和 f3。

  • f1 负责辨别橙色和绿色样本
  • f2 负责辨别橙色和紫色样本
  • f3 负责辨别绿色和紫色样本

在下图的例子中,f1 和 f2 都预测为橙色,f3 预测为紫色。依据少数准则失去的联合预测为橙色,如下图所示。

回到数字分类问题上,代码及后果如下:

from sklearn.multiclass import OneVsOneClassifier
from sklearn.linear_model import LogisticRegression
ovo_lr = OneVsOneClassifier(LogisticRegression(solver='lbfgs', max_iter=200) )
ovo_lr.fit(X_train, y_train)
OnevsOneClassifier(estimator=LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,intercept_scaling=1, max_iter=200, multi_class=‘warn’,n_jobs=None, penalty='12', random_state=None, solver='lbfgs’,tol=0.0001, verbose=6, warm_start=False),n_jobs=None)

10*9/2=45,10 类总共 45 个 OvO 分类器。

print(len(ovo_lr.estimators_) )        
ovo_lr.estimators_

后果如下:

45

(LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,intercept_scaling=1, max_iter=200, multi_class='warn',n_jobs=None, penalty='12', random_state=None, solver='lbfgs',tol=60.0001, verbose=0, warm_start=False),

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=200, multi_class='warn', n_jobs=None, penalty='l2', random_state=None, solver='lbfgs',tol=0.0001, verbose=0, warm_start=False),

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=200, multi_class='warn', n_jobs=None, penalty='12', random_state=None, solver='lbfgs', tol=60.0001, verbose=0, warm_start=False),

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=200, multi_class='warn', n_jobs=None, penalty="12", random_state=None, solver='lbfgs', tol=0.0001, verbose=0, warm_start=False),

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
...

训练集分类全对,测试集准确率 98%。

print (“OvO LR - Accuracy (Train): %.4g" % metrics.accuracy_score(y_train, ovo_Ir.predict(X_train)) )
print ("OvO LR - Accuracy (Test): %.4g" % metrics.accuracy_score(y_test, ovo_lr.predict(X_test}) )
# 运行后果
OvO LR - Accuracy (Train): 1
OvO LR - Accuracy (Test): 0.9806

② OneVsRestClassifier

在 OvA 中,把数据分成“某个”和“其余”

  • 图一,某个 = 橙色,其余 = 绿色和紫色
  • 图二,某个 = 绿色,其余 = 橙色和紫色
  • 图三,某个 = 紫色,其余 = 橙色和绿色

三分类分解成三个二分类,对应的分类器为 f1、f2 和 f3。

  • f1 预测负类,即预测绿色和紫色
  • f2 预测负类,即预测橙色和紫色
  • f3 预测正类,即预测紫色

三个分类器都预测了紫色,依据少数准则失去的预测是紫色,即阴天。

回到数字分类问题上,代码和后果如下:

from sklearn.multiclass import OneVsRestClassifier
ova_lr = OneVsRestClassifier(LogisticRegression(solver='lbfgs', max_iter=800) )
ova_lr.fit(X_train, y_train)
OnevsRestClassifier(estimator=LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=800, multi_class=‘warn’, n_jobs=None, penalty='12', random_state=None, solver='lbfgs’, tol=0.0001, verbose=6, warm_start=False), n_jobs=None)

10 类总共 10 个 OvA 分类器。

print(len(ova_lr.estimators_) )        
ova_lr.estimators_

后果如下:

10

[LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=800, multi_class='warn', n_jobs=None, penalty='12', random_state=None, solver='lbfgs',tol=0.0001, verbose=0, warm_start=False),

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=800, multi_class='warn', n_jobs=None, penalty='12', random_state=None, solver='lbfgs', tol=0.0001, verbose=0, warm_start=False),

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=800, multi_class=‘warn',
n_jobs=None, penalty='12', random_state=None, solver="lbfgs',
tol=0.0001, verbose=0, warm_start=False),

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=800, multi_class='warn', n_jobs=None, penalty='12', random_state=None, solver='lbfgs', tol=0.0001, verbose=0, warm_start=False),

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
...

训练集准确率简直 100%,测试集准确率 96%。代码与后果如下:

print (“OvA LR - Accuracy (Train): %.4g" % metrics.accuracy_score(y_train, ova_Ir.predict(X_train)) )
print ("OvA LR - Accuracy (Test): %.4g" % metrics.accuracy_score(y_test, ova_lr.predict(X_test}) )
OvA LR - Accuracy (Train): 6.9993
OvA LR - Accuracy (Test}: 6.9639

(2) 多标签分类

到目前为止,所有的样例都总是被调配到仅一个类。有些状况下,你兴许想让分类器给一个样例输入多个类别。在无人驾驶的利用中,在下图辨认出有车和指示牌,没有交通灯和人。

物体辨认是一个简单的深度学习问题,咱们在这里暂且不深入探讨。咱们先看一个简略点的例子,在手写数字的例子上,咱们特意为每个数字设计了两个标签:

  • 标签 1:奇数、偶数
  • 标签 2:小于等于 4,大于 4

咱们构建多标签y_train_multilabel,代码如下(OneVsRestClassifier 也能够用来做多标签分类):

from sklearn.multiclass import OneVsRestClassifier                 
y_train_multilabel = np.c_[y_train%2==0, y_train<=4]        
print(y_train_multilabel)
[[True True] [False False] [False False] 
... 
[False False] [False False] [False False]]

看下图训练集第 1 和 2 个图片是数字 4 和 5,对应下面两种标签后果为:

  • [True True]:4 是偶数,小于等于 4
  • [False False]:5 不是偶数,大于 4

咱们这次用 y_train_multilabel 来训练模型。代码如下

ova_ml = OneVsRestClassifier(LogisticRegression(solver='lbfgs', max_iter=800) )
ova_ml.fit(X_train, y_train_multilabel)
# 运行后果
OnevsRestClassifier(estimator=LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=800, multi_class=‘warn’, n_jobs=None, penalty='12', random_state=None, solver='lbfgs', tol=0.0001, verbose=6, warm_start=False), n_jobs=None)

有两个预计器,每个对应一个标签。

print(len(ova_ml.estimators_) )        
ova_ml.estimators_

运行后果如下:

2

[LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=800, multi_class=‘warn', n_jobs=None, penalty='12°, random_state=None, solver='lbfgs', tol=0.0001, verbose=0, warm_start=False),

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=800, multi_class='warn', n_jobs=None, penalty='l2', random_state=None, solver='lbfgs', tol=0.0001, verbose=0, warm_start=False) ]

展现一下测试集上 100 张图片。

fig, axes = plt.subplots(10, 10, figsize=(8, 8) )
fig.subplots_adjust(hspace=0.1, wspace=0.1)

for i, ax in enumerate(axes.flat):
    ax.imshow(X_test[i,:].reshape(8,8), cmap='binary', interpolation='nearest')
    ax.text(6.05, 0.05, str(y_test[i]), transform=ax.transAxes, color='blue')
    ax.set_xticks([])
    ax.set_yticks([])

第一张图片是数字 2,它是偶数(标签 1 为 true),小于等于 4(标签 2 为 true)。

print(y_test[:1] )        
print(ova_ml.predict(X_test[:1,:]) )
[2]
[[1 1]]

4.3 Multioutput 预计器

sklearn.multioutput能够解决多输入 (multi-output) 的分类问题。

多输入分类是多标签分类的泛化,在这里每一个标签能够是多类别 (大于两个类别) 的。一个例子就是预测图片每一个像素 (标签) 的像素值是多少(从 0 到 255 的 256 个类别)。

Multioutput 预计器有两个:

  • MultiOutputRegressor:多输入回归
  • MultiOutputClassifier:多输入分类

这里咱们只关注多输入分类。

(1) MultiOutputClassifier

首先引入 MultiOutputClassifier 和 RandomForestClassifier。

from sklearn.multioutput import MultiOutputClassifier
from sklearn.ensemble import RandomForestClassifier

在手写数字的例子上,咱们也为特意每个数字设计了多标签而且每个标签的类别都大于二。

  • 标签 1:小于等于 4,4 和 7 之间,大于等于 7(三类)
  • 标签 2:数字自身(十类)

代码如下:

y_train_1st = y_train.copy()
y_train_1st[y_train<=4] = 0
y_train_1st[np.logical_and{y_train>4, y_train<7) ] = 1
y_train_ist[y_train>=7] = 2

y_train_multioutput = np.c_[y_train_1st, y_train]
y_train_multioutput
# 运行后果
array([[0, 4],
        [1, 5],
        [2, 7],
        [1, 5],
        [2, 9],
        [2, 9]])

用含有 100 棵决策树的随机森林来解决这个多输出分类问题。

MO = MultiOutputClassifier(RandomForestClassifier(n_estimators=100) )
MO.fit(X_train, y_train_multioutput)
# 后果
MultiOutputClassifier(estimator=RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini', max_depth=None, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=100, n_jobs=None, oob_score=False, random_state=None, verbose=0, warm_start=False), n_jobs=None)

看看这个模型在测试集前五张照片上的预测。

MO.predict(X_test[:5,:] )
array([[0, 2],[0, 2],[0, 0],[2, 9],[1, 5]])

这个 ndarray 第一列是标签 1 的类别,第二列是标签 2 的类别。预测后果是这五张照片别离显示数字 2、2、0、9、5(标签 2),它们前三个数 2、2、0 都小于等于 4(标签 1 第一类),第四个数 9 大于等于 7(标签 1 第二类),而第五个数 5 在 4 和 7 之间(标签 1 第三类)。

再看看实在标签。

y_test_1st = y_test.copy()        
y_test_1st[y_test<=4] = 0        
y_test_1st[np.logical_and(y_test>4, y_test<7) ] = 1        
y_test_1st[y_test>=7] = 2                 
y_test_multioutput = np.c_[y_test_1st, y_test]                 
y_test_multioutput[:5]
array([[0, 2],[0, 2],[0, 0],[2, 9],[1, 5]])

比照参考后果标签,模型预测的后果还是很不错的。

4.4 Model Selection 预计器

模型抉择 (Model Selction) 在机器学习十分重要,它次要用于评估模型体现,常见的 Model Selection 预计器有以下几个:

  • cross_validate:评估穿插验证的后果。
  • learning_curve:构建与绘制学习曲线。
  • GridSearchCV:用穿插验证从超参数候选网格中搜寻出最佳超参数。
  • RandomizedSearchCV:用穿插验证从一组随机超参数搜寻出最佳超参数。

这里咱们只关注调节超参数的两个预计器,即 GridSearchCVRandomizedSearchCV。咱们先回顾一下穿插验证(更具体的解说请查看 ShowMeAI 文章 图解机器学习 | 模型评估办法与准则)。

(1) 穿插验证

K- 折穿插验证(K-fold cross validation set),指的是把整个数据集均匀但随机分成 K 份,每份大略蕴含 m / K 个数据(m 是总数据数)。

在这 K 份,每次选 K - 1 份作为训练集拟合参数,在剩下 1 份验证集上进行评估计算。因为遍历了这 K 份数据,因而该操作称为穿插验证。操作如下图所示

下图展现了两个调参的预计器:「网格搜寻 」和「 随机搜寻」。

网格搜寻调参 :参数 1 在[1,10,100,1000] 中取值,参数 2 在[0.01, 0.1, 1 10] 中取值,留神并不是等间距取值。模型在所有 16 组超参数上试验,选取穿插验证误差最小的参数。

随机搜寻调参 :依据指定散布随机搜寻,能够抉择独立于参数个数,比方 log(参数 1) 遵从 0 到 3 的均匀分布,log(参数 2)遵从 - 2 到 1 的均匀分布。

利用形式与参考代码如下:

from time import time
from scipy.stats import randint
from sklearn.model_selection import GridSearchCv
from sklearn.model_selection import RandomizedSearchcCv
from sklearn.ensemble import RandomForestClassifier

X, y = digits.data, digits.target
RFC = RandomForestClassifier(n_estimators=20)

# 随机搜寻 /Randomized Search
param_dist = {"max_depth": [3, 5],
                                "max_features": randint(1, 11),
                                "min_samples_split": randint(2, 11),
                                "criterion": ["gini", "entropy"]}
n_iter_search = 20
random_search = RandomizedSearchCv(RFC, param_distributions=param_dist, n_iter=n_iter_search, cv=5)}
start = time()
random_search.fit(X, y)
print("RandomizedSearchCv took %.2f seconds for %d candidates,parameter settings." % ((time() - start), n_iter_search))
print(random_search.best_params_)
print(random_search.best_score_)

# 网格搜寻 /Grid Search
param_grid = {"max_depth": [3, 5],
                                "max_features": [1, 3, 10],
                                "min_samples_ split": [2, 3, 10],
                                "criterion": ["gini", "entropy"]}
grid_search = GridSearchCV(RF, param_grid=param_grid, cv=5)
start = time()
grid_search.fit(X, y)

print("\nGridSearchcv took %.2f seconds for %d candidate parameter settings." % (time() - start, len(grid_search.cv_results_['params'])))
print(grid_search.best_params_)
print(grid_search.best_score_)

输入后果如下:

RandomizedSearchCv took 3.73 seconds for 20 candidates parameter settings.
{'criterion': 'entropy', '*max_depth': 5, 'max_features': 6, 'min_samples_split': 4}
0.8898163606010017

GridSearchCV took 2.30 seconds for 36 candidate parameter settings.
{'criterion': 'entropy', 'max_depth': 5, 'max_features': 10, 'min_samples_ split': 10}
0.841402337228714S5

这里咱们对代码做一个解释:

  • 前 5 行引入相应工具库。
  • 第 7 - 8 行筹备好数据 X 和 y,创立一个含 20 个决策树的随机森林模型。
  • 第 10-14 和 23-27 行为对随机森林的超参数「最大树深、最多特色数、最小可决裂样本数、决裂规范」构建候选参数散布与参数网格。
  • 第 15-18 行是运行 随机搜寻
  • 第 18-30 行是运行 网格搜寻

运行后果里:

  • 第一行输入每种追踪法运行的多少次和花的工夫。
  • 第二行输入最佳超参数的组合。
  • 第三行输入最高得分。

在本例中,随机搜寻 网格搜寻 用更短时间内找到一组超参数,取得了更高的得分。

4.5 Pipeline 预计器

Pipeline 预计器又叫流水线,把各种预计器串联 (Pipeline) 或并联 (FeatureUnion) 的形式组成一条龙服务。用好了它真的能大大提高效率。

(1) Pipeline

Pipeline 将若干个预计器按程序连在一起,比方:特征提取 → 降维 → 拟合 → 预测

Pipeline 的属性永远和最初一个预计器属性一样:

  • 如果最初一个预计器是预测器,那么 Pipeline 是预测器。
  • 如果最初一个预计器是转换器,那么 Pipeline 是转换器。

上面是一个简略示例,应用 Pipeline 来实现「填补缺失值 - 标准化」这两步的。咱们先构建含缺失值 NaN 的数据 X。

X = np.array([[56,40,30,5,7,10,9,np.NaN,12],
              [1.68,1.83,1.77,np.NaN,1.9,1.65,1.88,np.NaN,1.75]])
X = np.transpose(X)

咱们用以下流程组件构建 Pipeline:

  • 解决缺失值的转换器 SimpleImputer。
  • 做布局化的转换器 MinMaxScaler。
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import MinMaxScaler

pipe = Pipeline([('impute', SimpleImputer(missing_values=np.nan, strategy='mean')),
                ('normalize', MinMaxScaler())])

第 5 - 7 行创立了流水线,应用形式非常简单,在 Pipeline() 里输出 (名称, 预计器) 这个元组构建的流水线列表。在本例中 SimpleImputer 起名叫 impute,MinMaxScaler 起名叫 normalize。

因为最初一个预计器是转换器,因而 pipeline 也是个转换器。上面咱们来运行一下,咱们发现值都被填满了,而且两列也被标准化了。

X_proc = pipe.fit_transform(X)

来验证下面流水线的参数,咱们能够按程序来运行这两个转换器,后果是一样的。

X_impute = SimpleImputer(missing values=np.nan, strategy='mean').fit_transform(X)
X_impute
# 运行后果
array([[50, 1.68],
        [40, 1.83],
        [30, 1.77],
        [5, 1.78],
        [7, 1.9],
        [10, 1.65],
        [9, 1.88],
        [20.375, 1.78],
        [12, 1.75]])
X_normalize = MinMaxScaler().fit_transform( X_impute)
X_normalize

运行后果

array([[1., 0.12],
        [0.77777778, 0.72],
        [0.55555556, 6.48],
        [0.52, 1],
        [0.04444444, 1.],
        [0.11111111, 9.],
        [0.08888889, 6.92],
        [0.34166667, 6.52],
        [0.15555556, 0.4]])

(2) FeatureUnion

如果咱们想在一个节点同时运行几个预计器,咱们可用 FeatureUnion。在上面的例子中,咱们首先建设一个 DataFrame 数据,它有如下特点:

  • 前两列字段「智力 IQ」和「脾气 temper」都是类别型变量。
  • 后两列字段「支出 income」和「身高 height」都是数值型变量。
  • 每列中都有缺失值。
d= {'IQ' : ['high','avg','avg','low', high', avg', 'high', 'high',None],
'temper' : ['good', None,'good', 'bad', 'bad','bad', 'bad', None, 'bad'],
'income' : [50,40,30,5,7,10,9,np.NaN,12],
'height' : [1.68,1.83,1.77,np.NaN,1.9,1.65,1.88,np.NaN,1.75]}

X = pd.DataFrame(d)
X

后果如下:

咱们当初按下列步骤来荡涤数据。

  • 对类别型变量:获取数据 → 中位数填充 → 独热编码
  • 对数值型变量:获取数据 → 均值填充 → 标准化

下面两步是并行进行的。

首先咱们本人定义一个从 DataFrame 外面获取数据列的类,起名叫DataFrameSelector

from sklearn.base import BaseEstimator, TransformerMixin

class DataFrameSelector(BaseEstimator, TransformerMixin):
        def _init_(self, attribute_names):
                self.attribute_names = attribute_names
        def fit(self, X, y=None):
                return self
        def transform(self, X):
                return X[self.attribute_names].values

上述代码在 transform 函数中,咱们将输出的 DataFrame X 依据属性名称来获取其值。

接下来建设流水线full_pipe,它并联着两个流水线

  • categorical_pipe 解决分类型变量

    • DataFrameSelector 用来获取
    • SimpleImputer 用呈现最多的值来填充 None
    • OneHotEncoder 来编码返回非稠密矩阵
  • numeric_pipe 解决数值型变量

    • DataFrameSelector 用来获取
    • SimpleImputer 用均值来填充 NaN
    • normalize 来规范化数值

代码如下:

from sklearn.pipeline import Pipeline
from sklearn.pipeline import FeatureUnion
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import OneHotEncoder

categorical features = ['IQ', 'temper']
numeric_features = ['income', 'height']

categorical pipe = Pipeline([('select', DataFrameSelector(categorical_features)),
        ('impute', SimpleImputer(missing values=None, strategy='most_frequent')),
        ('one_hot_encode', OneHotEncoder(sparse=False))])

numeric_pipe = Pipeline([('select', DataFrameSelector(numeric_features)),
        ('impute', SimpleImputer(missing values=np.nan, strategy='mean')),
        ('normalize', MinMaxScaler())])

full_pipe = FeatureUnion( transformer_list=[('numeric_pipe', numeric_pipe),
        ('categorical_pipe', categorical_pipe)])

咱们打印后果如下:

X_proc = full_pipe.fit_transform(X)        
print(X_proc)
[[1. 0.12 0. 1. 0. 0. 1.] 
[0.77777778 0.72 1. 0. 0. 1. 0.] 
[0.55555556 0.48 1. 0. 0. 0. 1.] 
[0. 0.52 0. 0. 1. 1. 0.] 
[0.04444444 1. 0. 1. 0. 1. 0.] 
[0.11111111 0.   1. 0. 0. 1. 0.] 
[0.08888889 0.92 0. 1. 0. 1. 0.] 
[0.34166667 0.52 0. 1. 0. 1. 0.] 
[0.15555556 0.4  0. 1. 0. 1. 0.]]

5. 总结

上面咱们对下面解说到的 sklearn 工具库利用常识做一个总结。

5.1 SKLearn 五大准则

SKLearn 的设计下,它的次要 API 遵循五大准则

(1) 一致性

所有对象的接口统一且简略,在「预计器」中

  • 创立:model = Constructor(hyperparam)
  • 拟参:

    • 有监督学习:model.fit(X_train, y_train)
    • 无监督学习:model.fit(X_train)

在「预测器」中

  • 有监督学习里预测标签:y_pred = model.predict(X_test)
  • 无监督学习里识别模式:idx_pred = model.predict(Xtest)

在「转换器」中

  • 创立:trm = Constructor(hyperparam)
  • 获参:trm.fit(X_train)
  • 转换:X_trm = trm.transform(X_train)

(2) 可测验

所有预计器里设置的超参数和学到的参数都能够通过实例的变量间接拜访来测验其值,区别是超参数的名称最初没有下划线_,而参数的名称最初有下划线_。举例如下:

  • 通例:model.hyperparameter
  • 特例:SVC.kernel
  • 通例:model.parameter_
  • 特例:SVC.support_vectors_

(3) 规范类

SKLearn 模型承受的数据集的格局只能是「Numpy 数组」和「Scipy 稠密矩阵」。超参数的格局只能是「字符」和「数值」。
不承受其余的类!

(4) 可组成

模块都能反复「连在一起」或「并在一起」应用,比方两种模式流水线(pipeline)

  • 任意转换器序列
  • 任意转换器序列 + 预计器

(5) 有默认

SKLearn 给大多超参数提供了正当的默认值,大大降低了建模的难度。

5.2 SKLearn 框架流程

sklearn 的建模利用流程框架大略如下:

(1) 确定工作

是「有监督」的分类或回归?还是「无监督」的聚类或降维?确定好后根本就能晓得用 Sklearn 里哪些模型了。

(2) 数据预处理

这步最繁琐,要解决缺失值、异样值;要编码类别型变量;要正规化或标准化数值型变量,等等。然而有了 Pipeline 神器所有变得简略高效。

(3) 训练和评估

这步最简略,训练用预计器 fit() 先拟合,评估用预测器 predict() 来评估。

(4) 抉择模型

启动 ModelSelection 预计器里的 GridSearchCV 和 RandomizedSearchCV,抉择得分最高的那组超参数(即模型)。

参考资料

  • 图解机器学习算法 | 从入门到精通系列
  • SKLearn 官网:https://scikit-learn.org/stable/
  • AI 建模工具速查 |Scikit-learn 使用指南

ShowMeAI 系列教程举荐

  • 图解 Python 编程:从入门到精通系列教程
  • 图解数据分析:从入门到精通系列教程
  • 图解 AI 数学根底:从入门到精通系列教程
  • 图解大数据技术:从入门到精通系列教程
  • 图解机器学习算法:从入门到精通系列教程
  • 机器学习实战:手把手教你玩转机器学习系列

相干文章举荐

  • Python 机器学习算法利用实际
  • SKLearn 入门与简略利用案例
  • SKLearn 最全利用指南
  • XGBoost 建模利用详解
  • LightGBM 建模利用详解
  • Python 机器学习综合我的项目 - 电商销量预估
  • Python 机器学习综合我的项目 - 电商销量预估 < 进阶计划 >
  • 机器学习特色工程最全解读
  • 自动化特色工程工具 Featuretools 利用
  • AutoML 自动化机器学习建模

退出移动版