使用Scikit-learn开启机器学习之旅

Posted 盼小辉丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Scikit-learn开启机器学习之旅相关的知识,希望对你有一定的参考价值。

1. 机器学习基础

机器学习是令计算机根据可用数据执行相应策略而无需以明确的编程方式执行策略的一门学科。 在过去几十年间,由于可用数据的数量和质量呈指数级增长,同时高性能的计算设备也得到了快速发展,机器学习在图像识别、自然语言处理、推荐系统和自动驾驶等领域都取得了突破性进展。
机器学习的目标是构建强大的模型,可以操纵输入数据以预测输出,同时随着新数据的增加不断更新模型。传递到计算机中的任何信息或数据都可以被视为输入,通过机器学习模型得到的数据则被认为是输出
在机器学习中,输入数据也常被称为特征集,输出数据称为目标,特征集也称为特征空间。样本数据通常称为训练数据,使用样本数据训练模型完成后,它就可以对新数据进行预测,新数据通常也称为测试数据。机器学习主要可以分为两类:监督学习无监督学习
监督学习是指数据集同时包含输入(特征集)和期望的输出(目标)。也就是说,我们知道数据的特征,我们的目的是做出预测,监督学习侧重于基于从训练数据中学习到的已知特征进行预测。常见的监督学习包括分类与回归。为了对新数据进行分类回归,我们必须训练具有已知结果的数据,通过将数据映射到相应类别来对数据进行分类,通过查找特征集数据和目标数据之间的关系来进行数值预测。
对于无监督学习,数据集仅包含输入,但没有所需的输出(目标),其目标是探索数据并找到这些数据中的结构和模式。

2. Scikit-learn 机器学习库

2.1 Scikit-learn 介绍

Scikit-Learn 是机器学习的常用库,它包含很多实用工具和算法用于构建机器学习模型。它建立在 NumPySciPyMatplotlib 之上,是用于入门机器学习的绝佳工具。Scikit-Learn 库旨在使机器学习变得尽可能简单。Scikit-learn 主要是用 Python 编写的,并且使用 Numpy 进行高性能的线性代数和数组运算,其具有各种分类、回归和聚类算法。

2.2 Scikit-learn 安装

与其它标准第三方库一样,可以使用 pip 库安装 Scikit-Learn,在命令行中执行以下命令:

pip install scikit-learn

安装完成后,可以使用以下代码在 Python 中导入 Scikit-learn 库:

import sklearn

3. 监督学习

考虑到篇幅,对于各种机器学习算法背后的原因,本文并不会进行详细的介绍,重点在于介绍如何使用 Scikit-learn 库进行机器学习。我们将要介绍的感知机、逻辑回归、支持向量机、决策树和 K 最近邻居属于分类模型,而最后我们使用线性回归简单介绍 Scikit-learn 库在线性任务中的应用。

3.1 感知器

为了构建感知器 (Perceptron),我们将使用 Iris 数据集。Iris 也称鸢尾花卉数据集,其中包含 150 个数据样本,分为 3 类,每类 50 个数据,每个数据包含 4 个属性,可通过花萼长度,花萼宽度,花瓣长度,花瓣宽度4个属性将鸢尾花卉分类为 (SetosaVersicolourVirginica) 三类之一。鉴于Iris 数据集的流行性,其可以通过 Scikit-learn 加载,用于测试和试验算法。
我们将 150 个花卉的花瓣长度和花瓣宽度分配给特征矩阵 x,并将花卉相应的类别标签分配给数组 y

from sklearn import datasets
import numpy as np

iris = datasets.load_iris()
x = iris.data[:, [2, 3]]
y = iris.target
print('Class labels: ', np.unique(y))
# 输出结果
# Class labels:  [0 1 2]

np.unique(y) 函数返回存储在 iris.target 中的三个不同的类别标签,使用以上代码将鸢尾花类名称 Iris-setosaIris-versicolorIris-virginica 转换为整数 [0, 1, 2],使用整数标签可以提高计算性能,且内存占用更小;此外,将类标签编码为整数是大多数机器学习中的常见方法。
为了评估经过训练的模型在测试数据上的表现,我们首先将数据集拆分为训练和测试数据集:

from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, stratify=y)

使用 train_test_split 函数,将 xy 数组随机分成 30% 的测试数据和 70% 的训练数据,各自包含的数据量输出如注释所示,我们通过 stratify=y 参数返回与输入数据集具有相同比例类别的训练和测试子集。可以使用 NumPybincount 函数计算数组中每个值的出现次数,以验证拆分后的数据集:

print('Labels counts in y:', np.bincount(y))
# Labels counts in y: [50 50 50]
print('Labels counts in y_train:', np.bincount(y_train))
# Labels counts in y_train: [35 35 35]
print('Labels counts in y_test:', np.bincount(y_test))
# Labels counts in y_test: [15 15 15]

为了加速训练,使用 Scikit-learn 预处理模块中的 StandardScaler 类对特征进行标准化:

from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(x_train)
x_train_std = sc.transform(x_train)
x_test_std = sc.transform(x_test)

使用以上代码,我们加载了 StandardScaler 类,并初始化了 StandardScaler 对象 sc,使用 fit 方法,StandardScaler 从训练数据中估计每个特征维度的参数 μ μ μ (样本均值)和 σ σ σ (标准差)。 通过调用 transform 方法,使用估计的参数 μ μ μ σ σ σ 对训练和测试数据进行标准化。
标准化训练数据后,我们训练感知器模型:

from sklearn.linear_model import Perception
ppn = Perception(eta0=0.1)
ppn.fit(x_train_std, y_train)

在以上代码中,首先加载了 Perceptron 类,并初始化 Perceptron 对象 ppn ,然后通过 fit 方法训练模型,模型参数 eta0 为感知器使用的学习率。训练模型后,可以通过 predict 方法进行预测:

y_pred = ppn.predict(x_test_std)
print('Misclassified examples: %d' % (y_test != y_pred).sum())
# Misclassified examples: 4

我们可以看到感知器在 45 个测试数据中,将 4 个花卉样本错误分类。Scikit-learn 中还包括多种不同的性能指标,用于评估模型性能。例如,我们可以计算感知器在测试数据集上的分类准确率如下:

from sklearn.metrics import accuracy_score
print('Accuracy: %.3f' % accuracy_score(y_test, y_pred))
# Accuracy: 0.911
print('Accuracy: %.3f' % ppn.score(x_test_std, y_test))
# Accuracy: 0.911

最后,我们编写 plot_decision_regions 函数来绘制感知器模型的决策平面:

from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt
def plot_decision_regions(x, y, classifier, test_idx=None, resolution=0.02):
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])
    x1_min, x1_max = x[:, 0].min() - 1, x[:, 0].max() + 1
    x2_min, x2_max = x[:, 1].min() - 1, x[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
    np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())
    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=x[y == cl, 0], y=x[y == cl, 1], alpha=0.8, c=colors[idx], marker=markers[idx], label=cl, edgecolor='black')
    if test_idx:
        x_test, y_test = x[test_idx, :], y[test_idx]
        plt.scatter(x_test[:, 0], x_test[:, 1], c='', edgecolor='black', alpha=1.0, linewidth=1, marker='o', s=100, label='test set')

调用 plot_decision_regions,绘制决策平面:

x_combined_std = np.vstack((x_train_std, x_test_std))
y_combined = np.hstack((y_train, y_test))
plot_decision_regions(x=x_combined_std, y=y_combined, classifier=ppn, test_idx=range(105, 150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.show()

如上图所示,三种花卉并不能被线性感知器完美地进行区分,这就是我们需要在感知器中引入非线性的原因。

3.2 逻辑回归

接下来,我们现在实现另一种简单但更强大的线性的二分类算法:逻辑回归 (Logistic regression),尽管名为逻辑回归,但它是分类模型,而非回归模型。逻辑回归可以很容易地扩展至多分类问题,称为多元逻辑回归或 Softmax 回归。
为了解释逻辑回归背后的想法,我们首先介绍概率: p 1 − p \\frac p 1-p 1pp 其中 p p p 代表正向事件 (positive event) 的概率。正向事件并不一定意味着是好的事件,而是指我们要预测的事件,例如患者患某种疾病的概率;我们可以将正向事件视为类标签 y = 1 y = 1 y=1。然后,我们可以定义 logit 函数,它是概率的对数:
l o g i t ( p ) = l o g p 1 − p logit(p)=log\\frac p 1-p logit(p)=log1pp
其中, l o g log log 表示自然对数,因为它是计算机科学中的常用约定,我们可以用它来表示特征值和对数概率之间的线性关系:
l o g i t ( p ( y = 1 ∣ x ) ) = w 0 x 0 + w 1 x 1 + . . . + w n x n = ∑ i = 0 m w i x i = w T x logit(p(y=1|x))=w_0x_0+w_1x_1+...+w_nx_n=\\sum ^m _i=0 w_ix_i=w^Tx logit(p(y=1x))=w0x0+w1x1+...+wnxn=i=0mwixi=wTx
其中 p ( y = 1 ∣ x ) p(y=1|x) p(y=1x) 表示给定特征的样本 x x x 属于类别 1 的条件概率。这样,我们就可以对某个样本属于特定类别的概率进行预测。
简单的了解了逻辑回归的原理后,我们学习如何使用 Scikit-learn 中的 LogisticRegression 类实现逻辑回归,参数 C 用于指定正则化强度倒数,防止过拟合,参数 solver 用于指定优化器。该类还支持使用 multi_class 参数用于多分类问题。本节中,我们依旧使用 Iris 数据集训练模型。为了进行多分类,我们设置 multi_class='multinomial'。除此之外,multi_class 还有一个重要的可选值 'ovr' 进行比较。在实践中,通常对互斥类使用可选值 multinomial,例如在 Iris 数据集中的类别即为互斥类,“互斥”意味着每个训练样本只能属于一个类,多标签分类中一个训练样例可以属于多个别,例如一张图片中包含人、车和路灯等,则此图片可以有三个不同标签。

from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(C=100., solver='lbfgs', multi_class='multinomial')
lr.fit(x_train_std, y_train)
plot_decision_regions(x_combined_std, y_combined, classifier=lr, test_idx=range(105, 150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()

在训练数据上拟合模型后,绘制决策区域、训练数据和测试数据,如下图所示:


可以使用 predict_proba 方法计算训练样本属于某个类别的概率。例如,预测测试数据集中前三个样本的概率如下:

print(lr.predict_proba(x_test_std[:3, :]))

以上代码输出结果如下所示:

[[5.03465809e-06 9.33980393e-01 6.60145727e-02]
 [9.98750558e-01 1.24944182e-03 9.03958143e-16]
 [1.15923447e-14 1.73752823e-05 9.99982625e-01]]

第一行对应第一朵花的类别概率,第二行对应第二朵花的类成员概率,依此类推。第一行中的最大值约为 0.93,这意味着第一个示例属于第 2 类,预测概率为 93%。因此,我们可以通过使用 NumPyargmax 函数识别每行中最大的列来获得预测的类标签:

print(lr.predict_proba(X_test_std[:3, :]).argmax(axis=1))

返回的类别索引显示如下:

array([1, 0, 2])

在以上代码示例中,我们计算条件概率,并使用 NumPyargmax 函数手动将它们转换为类标签,我们也可以使用 predict 直接获取类标签:

print(lr.predict(X_test_std[:3, :]))
# array([2, 0, 0])

3.3 支持向量机

支持向量机 (Support Vector Machines, SVM) 是另一种强大的机器学习算法,它是感知器的扩展。 使用感知器算法,我们的目标是最大限度地减少了错误分类概率,在 SVM 中,我们的优化目标是最大化边距 (margin),边距定义为超平面(决策边界)与最接近该超平面的训练样本之间的距离,即所谓的支持向量。简单了解 SVM 背后的基本思想后,我们训练 SVM 模型来对 Iris 数据集中的不同花朵进行分类:

from sklearn.svm import SVC
svm = SVC(kernel='linear', C=1.0)
svm.fit(x_train_std, y_train)
plot_decision_regions(x_combined_std, y_combined, classifier=svm, test_idx=range(105, 150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()

通过执行以上代码在 Iris 数据集上训练分类器后可视化,SVM 的三个决策区域如下图所示:

3.4 决策树

决策树分类器的执行过程具有很好的可解释性,正如其名称所示,我们可以将此模型视为通过解决一系列问题做出决策,以此来分解数据。
基于训练数据集中的特征,决策树模型学习一系列问题来推断样本的类别标签。例如在 Iris 数据集中,我们可以沿萼片宽度特征轴定义一个阈值并提出一个二元问题:萼片宽度是否 ≥2.8 cm?通过回答一系列问题完成样本数据的分类。
使用决策树算法,从树根开始,在令最大信息增益 (Information Gain, IG) 的特征上分割数据。在一个迭代过程中,我们可以在每个子节点重复这个分裂过程,直到叶子节点。这意味着每个节点的训练样本都属于同一个类。在实践中,这可能会导致树的节点过多且深度较深,这很容易导致过拟合。因此,我们通常通过设置树的最大深度来修剪树。
决策树可以通过将特征空间划分为矩形来构建复杂的决策边界。但是,决策树越深,决策边界就越复杂,这很容易导致过拟合。接下来,我们使用 Scikit-learn 训练一个最大深度为 4 的决策树,使用 Gini 不纯度作为度量标准。尽管出于可视化目的可能需要对特征进行缩放,但特征缩放对于决策树算法并非必要:

from sklearn.tree import DecisionTreeClassifier
tree_model = DecisionTreeClassifier(criterion='gini', max_depth=4)
tree_model.fit(x_train, y_train)
x_combined = np.vstack((x_train, x_test))
y_combined = np.hstack((y_train, y_test))
plot_decision_regions(x_combined, y_combined, classifier=tree_model, test_idx=range(105, 150))
plt.xlabel('petal length [cm]')
plt.ylabel('petal width [cm]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()

执行代码后,我们得到决策树的决策边界:


另外,我们可以在 Scikit-learn 轻松可视化训练完成后的决策树模型:

from sklearn import tree
tree.plot_tree(tree_model)
plt.show()

机器学习系列6 使用Scikit-learn构建回归模型:简单线性回归多项式回归与多元线性回归

机器学习系列5 利用Scikit-learn构建回归模型:准备和可视化数据(保姆级教程)

机器学习包Scikit-learn

机器学习-scikit-learn

郑捷《机器学习算法原理与编程实践》学习笔记(第三章 决策树的发展)_Scikit-learn与回归树

[机器学习与scikit-learn-19]:算法-逻辑回归-概述与原理