目前,Python 有不少可以实现各种机器学习算法的程序库。Scikit-Learn(http://scikit-learn.org)是最流行的程序包之一,它为各种常用机器学习算法提供了高效版本。Scikit-Learn 不仅因其干净、统一、管道命令式的 API 而独具特色,而且它的在线文档又实用、又完整。这种统一性的好处是,只要你掌握了 Scikit-Learn 一种模型的基本用法和语法,就可以非常平滑地过渡到新的模型或算法上。

    此次对 Scikit-Learn 的 API 进行概述。真正理解这些 API 的组成部

分将对更深入地理解机器学习算法与技巧大有裨益。


SKlearn  的数据表示

01 / 数据表

Scikit-Learn 认为数据表示最好的方法就是用数据的形式。


基本的数据表就是二维网格数据,其中的每一行表示数据集中的每个样本,而列表示构成每个样本的相关特征。例如 Ronald Fisher 在1936 年对鸢尾花数据集

https://en.wikipedia.org/wiki/Iris_flower_data_set)的经典分析。我们用 Seaborn 程序库

https://stanford.edu/~mwaskom/software/seaborn/)下载数据并加载到 Pandas 的 DataFrame 中:


import seaborn as sns
iris = sns.load_dataset('iris')
iris.head()

Python机器学习之“Scikit-Learn”_java

其中的每行数据表示每朵被观察的鸢尾花,行数表示数据集中记录的鸢尾花总数。一般情况下,会将这个矩阵的行称为样本(samples),行数记为 n_samples

同样,每列数据表示每个样本某个特征的量化值。一般情况下,会将矩阵的列称为特征(features),列数记为 n_features



02 /特征矩阵

      这个表格布局通过二维数组或矩阵的形式将信息清晰地表达出来,所以我们通常把这类矩阵称为 特征矩阵(features matrix)。特征矩阵通常被简记为变量 X。它是维度为 [n_samples,n_features] 的二维矩阵,通常可以用 NumPy 数组或 Pandas 的DataFrame 来表示,不过 Scikit-Learn 也支持 SciPy 的稀疏矩阵

      样本(即每一行)通常是指数据集中的每个对象。例如,样本可能是一朵花、一个人、一篇文档、一幅图像,或者一首歌、一部影片、一个天体,甚至是任何可以通过一组量化方法进行测量的实体。

      特征(即每一列)通常是指每个样本都具有的某种量化观测值。一情况下,特征都是实数,但有时也可能是布尔类型或者离散值。



03 / 目标数组

      除了特征矩阵 X 之外,我们还需要一个标签或目标数组,通常简记为 y目标数组一般是一维数组,其长度就是样本总数n_samples,通常都用一维的 NumPy 数组或 Pandas 的 Series 示。目标数组可以是连续的数值类型,也可以是离散的类型 / 标签。虽然有些 Scikit-Learn 的评估器可以处理具有多目标值的二维[n_samples, n_targets] 目标数组,但此处基本上只涉及常见的一维目标数组问题。

      如何区分目标数组的特征与特征矩阵中的特征列,一直是个问题。标数组的特征通常是我们希望从数据中预测的量化结果借用统计学的术语,y 就是因变量以前面的示例数据为例,我们需要通过其他测量值来建立模型,预测花的品种(species),而这里的species 列就可以看成是目标数组。

      知道这一列是目标数组之后,就可以用 Seaborn(对数据进行可视化了。

%matplotlib inline
import seaborn as sns; sns.set()
sns.pairplot(iris, hue='species', size=1.5);


# pair是成对的意思,pairplot主要展现的是变量两两之间的关系(线性或非线性,有无较为明显的相关关系),画两两特征图。
函数原型:seaborn.pairplot(data,
                        hue=None, hue_order=None
                        palette=None, vars=None
                        x_vars=None, y_vars=None
                        kind=’scatter’, diag_kind=’hist’, 
                        markers=None, size=2.5, aspect=1
                        dropna=True, plot_kws=None
                        diag_kws=None, grid_kws=None)
常用参数介绍:
data:必不可少的数据
hue: 针对某一字段进行分类,用一个特征来显示图像上的颜色,类似于打标签
kind:用于控制非对角线上的图的类型,可选"scatter"与"reg"
diag_kind:控制对角线上的图的类型,可选"hist"与"kde"
palette:控制色调,palette="husl"
marker: 控制散点的样式,每个label的显示图像变动,,markers=["+", "s", "D"]
vars:只留几个特征两两比较
plot_kws:用于控制非对角线上的图的样式,plot_kws=dict(s=50,edgecolor="w",color="g",alpha=.5)
diag_kws:用于控制对角线上图的样式,diag_kws=dict(shade=True,color="r")

Python机器学习之“Scikit-Learn”_java_02

在使用 Scikit-Learn 之前,我们需要从 DataFrame 中抽取特征矩阵目标数组。可以用Pandas DataFrame 基本操作来实现:

Python机器学习之“Scikit-Learn”_java_03

Python机器学习之“Scikit-Learn”_java_04

有了适当的数据形式之后,就可以开始学习 Scikit-Learn 的评估器API 了。




scikit-learn的评估器API




Scikit-Learn API 主要遵照以下设计原则,Scikit-Learn API 文档也对此

有所概述。

统一性:所有对象使用共同接口连接一组方法和统一的文档。


内省:所有参数值都是公共属性。


限制对象层级:只有算法可以用 Python 类表示。数据集都用标准数据类型(NumPy 数组、Pandas DataFrame、SciPy 稀疏矩阵)表示,参数名称用标准的 Python 字符串。

函数组合:许多机器学习任务都可以用一串基本算法实现,Scikit-Learn 尽力支持这种可能。

明智的默认值:当模型需要用户设置参数时,Scikit-Learn 预先定义适当的默认

值。

只要你理解了这些设计原则,就会发现 Scikit-Learn 非常容易使用。Scikit-Learn 中的所有机器学习算法都是通过评估器 API 实现的,它为各种机器学习应用提供了统一的接口。





01 / API基础知识

Scikit-Learn 评估器 API 的常用步骤如下所示:

(1) 通过从 Scikit-Learn 中导入适当的评估器类,选择模型类

(2) 用合适的数值对模型类进行实例化配置模型超参数

(hyperparameter)。

(3) 整理数据,通过前面介绍的方法获取特征矩阵X和目标数组y

(4) 调用模型实例的 fit() 方法对数据进行拟合

(5) 对新数据应用模型:

  • 有监督学习模型中,通常使用 predict() 方法预测新数据

的标签

  • 无监督学习模型中,通常使用 transform() 或 predict()

方法转换或推断数据的性质



下面按照步骤来演示几个使用了有监督学习方法和无监督学习方法的示例。


02 有监督学习示例:简单线性回归

让我们来演示一个简单线性回归的建模步骤——最常见的任务就是

为散点数据集 (x, y) 拟合一条直线。我们将使用下面的样本数据来

演示这个回归示例


import matplotlib.pyplot as plt
import numpy as np

    #numpy.random.RandomState()是一个伪随机数生成器
rng = np.random.RandomState(42)

#np.random.rand() 可以返回一个或一组服从“0~1”均匀分布的随机样本值。随机样本取值范围是[0,1),不包括1。 
x = 10 * rng.rand(50)  #  50个
y = 2 * x - 1 + rng.randn(50)
plt.scatter(x, y);

Python机器学习之“Scikit-Learn”_java_05

有了数据,就可以将前面介绍的步骤付诸实现了,先一步步来。

(1) 选择模型类

  在 Scikit-Learn 中,每个模型类都是一个 Python 类。因此,假如我们想要计算一个简单线性回归模型,那么可以直接导入线性回归模型类:

from sklearn.linear_model import LinearRegression


除了简单线性模型,常用的线性模型还有许多,具体内容请参sklearn.linear_model 模块文档(http://scikit-learn.org/stable/modules/linear_model.html)。


(2) 选择模型超参数请注意,模型类与模型实例不同。

  当我们选择了模型类之后,还有许多参数需要配置。根据不同模型的不同情况,你可能需要回答以下问题。

  • 我们想要拟合偏移量(即直线的截距)吗?

  • 我们需要对模型进行归一化处理吗?

  • 我们需要对特征进行预处理以提高模型灵活性吗?

  • 我们打算在模型中使用哪种正则化类型?

  • 我们打算使用多少模型组件 ?

  有一些重要的参数必须在选择模型类时确定好。这些参数通常称为超参数,即在模型拟合数据之前必须被确定的参数。Scikit-Learn 中,我们通常在模型初始化阶段选择超参数。后续介绍如何定量地选择超参数。

  对于现在这个线性回归示例来说,可以实例化LinearRegression 类并用 fit_intercept 超参数设置是否想要拟合直线的截距

Python机器学习之“Scikit-Learn”_java_06

需要注意的是,对模型进行实例化其实仅仅是存储了超参数的。我们还没有将模型应用到数据上:Scikit-Learn 的 API 对选择模型和将模型应用到数据区别得很清晰。


(3) 将数据整理成特征矩阵和目标数组

  前面介绍了 Scikit-Learn 的数据表示方法,它需要二维特征矩阵和一维目标数组。虽然我们的目标数组已经有了 y(长度为n_samples 的数组),但还需要将数据 x 整理成 [n_samples,n_features] 的形式。在这个示例中,可以对一维数组进行简单的维度变换:

Python机器学习之“Scikit-Learn”_java_07


(4) 用模型拟合数据

  现在就可以将模型应用到数据上了,这一步通过模型的 fit()方法即可完成:

Python机器学习之“Scikit-Learn”_java_08

     fit() 命令会在模型内部进行大量运算,运算结果将存储在型属性中,供用户使用。在 Scikit-Learn 中,所有通过 fit() 方法获得的模型参数都带一条下划线。例如,在线性回归模型中,模型参数如下所示:

Python机器学习之“Scikit-Learn”_java_09


这两个参数分别表示对样本数据拟合直线的斜率和截距。与前面样本数据的定义(斜率 2、截距 -1)进行比对,发现拟合结果与样本非常接近。

  模型参数的不确定性是机器学习经常遇到的问题。一般情况下,Scikit-Learn 不会为用户提供直接从模型参数获得结论的工具;与其将模型参数解释为机器学习问题,不如说它更像统计建模问题。机器学习的重点并不是模型的预见性。如果你想要对模型拟合参数的意义和其他相关参数分析工具有更深入的理解,请参考StatsModelsPython 程序包(http://statsmodels.sourceforge.net/)


(5) 预测新数据的标签

  模型训练出来之后,有监督机器学习的主要任务就变成了对不属于训练集的新数据进行预测。在 Scikit-Learn 中,我们用predict() 方法进行预测。“新数据”是特征矩阵的 x 坐标值,我们需要用模型预测出目标数组的 y 轴坐标:

Python机器学习之“Scikit-Learn”_java_10


通常都是用一些基准指标来验证模型的学习效果,我们将在以后的示例中介绍这些指标。



03 有监督学习示例:鸢尾花数据分类

      再介绍一个有监督学习示例,还是用前面介绍过的鸢尾花数据集。这个示例的问题是:如何为鸢尾花数据集建立模型,先用一部分数据进行训练,再用模型预测出其他样本的标签?

     我们将使用非常简单的高斯朴素贝叶斯(Gaussian naive Bayes)法完成这个任务,这个方法假设每个特征中属于每一类的观测值都符合高斯分布。因为高斯朴素贝叶斯方法速度很快,而且不需要选择超参数,所以通常很适合作为初步分类手段,在借助更复杂的模型进行优化之前使用。

     由于需要用模型之前没有接触过的数据评估它的训练效果,因此得先将数据分割成训练集(training set)和测试集(testing set)。虽然完全可以手动实现分割数据集,但是借助train_test_split函数会更方便:

from  sklearn.model_selection import train_test_split
Xtrain, Xtest, ytrain, ytest = train_test_split(X_iris, y_iris,
                                                random_state=1)
from sklearn.naive_bayes import GaussianNB # 1.选择模型类
model = GaussianNB() # 2.初始化模型
model.fit(Xtrain, ytrain) # 3.用模型拟合数据
y_model = model.predict(Xtest) # 4.对新数据进行预测


最后,用 accuracy_score 工具验证模型预测结果的准确率(预测的所有结果中,正确结果占总预测样本数的比例):

from sklearn.metrics import accuracy_score
accuracy_score(ytest, y_model)

0.9736842105263158


准确率竟然高达 97%,看来即使是非常简单的分类算法也可以有效地学习这个数据集!


04 无监督学习示例:鸢尾花数据降维

      介绍一个无监督学习问题——对鸢尾花数据集进行降维,以便能更方便地对数据进行可视化。前面介绍过,鸢尾花数据集由四维度构成,即每个样本都有四个维度。

     降维的任务是要找到一个可以保留数据本质特征的低维矩阵来表示高维数据。降维通常用于辅助数据可视化的工作,毕竟用二维数据画图比用四维甚至更高维的数据画图更方便!

     下面将使用主成分分析(principal component analysis,PCA方法,这是一种快速线性降维技术。我们将用模型返回两个主成分,也就是用二维数据表示鸢尾花的四维数据。同样按照前面介绍过的建模步骤进行:

from sklearn.decomposition import PCA # 1.选择模型类
model = 
PCA(n_components=2) # 2.设置超参数,初始化模型
model.fit(X_iris) # 3.拟合数据,注意这里不用y变量
X_2D = model
.transform(X_iris) # 4. 将数据转换为二维


现在来画出结果。快速处理方法就是先将二维数据插入到鸢尾花的DataFrame 中,然后用 Seaborn 的 lmplot 方法画图:

iris['PCA1'] = X_2D[:, 0]
iris['PCA2'] = X_2D[:, 1]
sns.lmplot("PCA1""PCA2", hue='species', data=iris, fit_reg=False);

Python机器学习之“Scikit-Learn”_java_11

      从二维数据表示图可以看出,虽然 PCA 算法根本不知道花的种类标签,但不同种类的花还是被很清晰地区分开来!这表明用一种比较简单的分类方法就能够有效地学习这份数据集,就像前面看到的那样。


05 无监督学习示例:鸢尾花数据聚类

      再看看如何对鸢尾花数据进行聚类。聚类算法是要对没有任何标签的数据集进行分组。我们将用一个强大的聚类方法——高斯混合模型(Gaussian mixture model,GMM)。GMM 模型试图将数据构造成若干服从高斯分布的概率密度函数簇。用以下方法拟合高斯混合模型:

from sklearn.mixture import GaussianMixture # 1.选择模型类
model = 
GaussianMixture(n_components=3,
         
covariance_type='full') # 2.设置超参数,初始化模型
model.fit(X_iris) # 3.拟合数据,注意不需要y变量
y_gmm = model.predict(X_iris) # 4. 确定簇标签

和之前一样,将簇标签添加到鸢尾花的 DataFrame 中,然后用Seaborn 画出结果:

iris['cluster'] = y_gmm
sns.lmplot("PCA1""PCA2", data=iris, hue='species',
           col='cluster', fit_reg=False);

Python机器学习之“Scikit-Learn”_java_12

     根据簇数量对数据进行分割,就会清晰地看出 GMM 算法的训练效果:setosa(山鸢尾花)类的花在簇 0 中被完美地区分出来,唯一的遗憾是第三幅图中 versicolor(变色鸢尾花)和 virginicaI(维吉亚鸢尾花)还有一点混淆。这就说明,即使没有专家告诉我们每朵花的具体种类,但由于每种花的特征差异很大,因此我们也可以通过简单的聚类算法自动识别出不同种类的花!这种算法还可以帮助专家们探索观察样本之间的关联性。