机器学习实战——基于Scikit-Learn和TensorFlow 阅读笔记 之 第三章:分类

《机器学习实战——基于Scikit-Learn和TensorFlow》
这是一本非常好的机器学习和深度学习入门书,既有基本理论讲解,也有实战代码示例。
我将认真阅读此书,并为每一章内容做一个知识笔记。
我会摘录一些原书中的关键语句和代码,若有错误请为我指出。

在这里插入图片描述

第三章 分类

1 MNIST

MNIST数据集,一组由美国高中生和人口调查局员工手写的70000个数字的图片。每张图片都用其代表的数字标记。机器学习领域的Hello World!

获取MNIST数据集。

from sklearn.datasets import fetch_mldata

mnist = fetch_mldata('MNIST original')

scikit-learn加载的数据集通常具有类似的字典结构,包括:
DESCR键,描述数据集
data键,包含一个数组,每个实例为一行,每个特征为一列
target键,包含一个带有标记的数组

显示某实例的图片
some_digit = X[36000]
some_digit_image = some_digit.reshape(28, 28)
plt.imshow(some_digit_image, cmap = mpl.cm.binary,
           interpolation="nearest")
plt.axis("off")

save_fig("some_digit_plot")
plt.show()

将训练数据洗牌,保证交叉验证时所有的折叠都差不多,且保证某些对训练实例顺序敏感的机器学习算法。

将训练数据洗牌 
import numpy as np

shuffle_index = np.random.permutation(60000)
X_train, y_train = X_train[shuffle_index], y_train[shuffle_index]

2 训练一个二元分类器

先简化问题来识别5和非5.

y_train_5 = (y_train == 5)
y_test_5 = (y_test == 5)

一个好的初始选择是随机梯度下降(SGD)分类器,使用scikit-learn的SGDClassifier类即可。
这个分类器的优势是,能够有效处理非常大型的数据集,这是因为SGD一次处理一个实例,非常适合在线学习。

from sklearn.linear_model import SGDClassifier

sgd_clf = SGDClassifier(max_iter=5, tol=-np.infty, random_state=42)
sgd_clf.fit(X_train, y_train_5)

训练好后用来预测。

sgd_clf.predict([some_digit])

3 性能考核

评估分类器比评估回归器困难得多。

3.1 使用交叉验证测量精度

可以使用cross_val_score()函数来评估SGDClassifier模型,采用k-fold交叉验证。

from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring="accuracy")

但是处理 偏斜数据 ,准确率无法准确地衡量分类器的准确性能

3.2 混淆矩阵

混淆矩阵 的总体思路就是统计A类别被分成B类别的次数。
要想知道分类器将数字3和数字5混淆多少次,只需要通过混淆矩阵的第5行第3列来查看。

from sklearn.metrics import confusion_matrix

confusion_matrix(y_train_5, y_train_pred)

一个完美的分类器只有真正类和真负类,所以它的混淆矩阵只会在其对角线(左上到右下)上有非零值。

其中,正类预测的准确率是一个有趣的指标,也称精度。
= T P T P + F P 精度=\frac{TP}{TP+FP}
TP是真正类的数量,DP是假正类的数量。

但是只考虑精度的话,分类器会忽略正类实例之外的所有内容。

所以还要考虑召回率,也称灵敏度或真正类率TPR。
= T P T P + F N 召回率=\frac{TP}{TP+FN}
FN是假负率的数量。

from sklearn.metrics import precision_score, recall_score

precision_score(y_train_5, y_train_pred)
recall_score(y_train_5, y_train_pred)

3.3 精度和召回率

因此可以将精度和召回率组成一个单一的指标,称为F1分数。
F1是精度和召回率的谐波平均值,谐波平均值和一般的平均值相比会给予较低的值更高的权重,因此,只有当召回率和精度都很高时,分类器才能得到较高的F1分数。

F 1 = 2 1 / + 1 / = 2 + F_1=\frac{2}{1/精度+1/召回率}=2*\frac{精度*召回率}{精度+召回率}

F1分数对那些具有相近的精度和召回率的分类器更为有利,不一定符合我们偏重精度或召回率的预期。
但是却不能同时增加其中一个而降低另一个,这称为精度/召回率权衡。

3.4 精度/召回率权衡

scikit-learn不允许直接设置阈值,但是可以访问它用于预测的决策分数decision_function()。它返回每个实例的决策分数,然后就可以根据这些分数,使用任意的阈值进行预测了。

可以使用precision_recall_curve()函数来计算所有可能的阈值的精度和召回率。
最后使用Matplotlib来绘制精度和召回率相对于阈值的函数图。

from sklearn.metrics import precision_recall_curve

precisions, recalls, thresholds = precision_recall_curve(y_train_5, y_scores)

def plot_precision_recall_vs_threshold(precisions, recalls, thresholds):
    plt.plot(thresholds, precisions[:-1], "b--", label="Precision", linewidth=2)
    plt.plot(thresholds, recalls[:-1], "g-", label="Recall", linewidth=2)
    plt.xlabel("Threshold", fontsize=16)
    plt.legend(loc="upper left", fontsize=16)
    plt.ylim([0, 1])

plt.figure(figsize=(8, 4))
plot_precision_recall_vs_threshold(precisions, recalls, thresholds)
plt.xlim([-700000, 700000])
save_fig("precision_recall_vs_threshold_plot")
plt.show()

3.5 ROC曲线

受试者工作特征曲线(ROC)。
绘制的是TPR和FPR的关系。

from sklearn.metrics import roc_curve

fpr, tpr, thresholds = roc_curve(y_train_5, y_scores)

def plot_roc_curve(fpr, tpr, label=None):
    plt.plot(fpr, tpr, linewidth=2, label=label)
    plt.plot([0, 1], [0, 1], 'k--')
    plt.axis([0, 1, 0, 1])
    plt.xlabel('False Positive Rate', fontsize=16)
    plt.ylabel('True Positive Rate', fontsize=16)

plt.figure(figsize=(8, 6))
plot_roc_curve(fpr, tpr)
save_fig("roc_curve_plot")
plt.show()

优秀的分类器越靠近左上越好。

可以测量曲线下面的面积AUC来评估。
完美的分类器的AUC为1,随机的分类器的AUC为0.5。

from sklearn.metrics import roc_auc_score

roc_auc_score(y_train_5, y_scores)

ROC与精度/召回率曲线非常相似,当正类少或者更关注假正类而不是假负类时,应该选择后者,否则使用前者。

4 多类别分类器

有一些算法(如随进森林或朴素贝叶斯分类器)可以直接处理多个类别。
也有些严格的二元的分了器(如支持向量机或线性分类器)。

比如将数字图片分成十类,一种方法是训练十个二元分类器,哪个分类器给分最高就将其分类为哪类。这称为一对多(OvA)策略。

另一种方法是对每一对数字训练一个二元分类器,称为一对一(OvO)策略。如果存在N个类别,那么需要训练N*(N-1)/2个分类器。
其优点在于只需要用到部分训练集对其必须区分的两个类别进行训练。

有一些算法(如SVM)在数据规模扩大时表现糟糕,因此对于这类算法,OvO是一个优先选择,由于在较小的训练集上分别训练多个分类器比在大型数据集上训练少数分类器快得多。
但是对大多数二元分了器来说,OvA策略还是更好的选择。

5 错误分析

通过对错误进行分析从而改进模型。

首先看混淆矩阵。
在这里插入图片描述
每行代表实际类别,而每列代表预测类别。
浅色的代表错误较多的情况。

分析单个的错误也可以为分类器提供洞察:它在做什么?它为什么会失败?但这通常更加困难和耗时。

6 多标签分类

有些实例可能属于多个类别,输出多个二元标签的分类系统称为多标签分类系统。

评估多标签分类器的方法很多,如何选择正确的度量指标取决于你的项目。

7 多输出分类

多输出-多分类分类是多标签分类的泛化,其标签也可以是多种类别的。

分类和回归之间的界限有时很模糊。 比如预测像素强度更像是回归任务而不是分类。 而多输出系统也不仅仅限于分类任务,可以让一个系统给每个实例输出多个标签,同时包括类别标签和值标签。