hands-on Machine Learning with sklearn

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jiaoyangwm/article/details/82387883

一、机器学习概览

  1. 如何定义机器学习?

    机器学习是通过一定的样本来学习一个模型,来对未知数据的输出做预测。

  2. 机器学习可以解决的四类问题?

    没有逻辑解、手工调整规则、构建适应环境波动的系统、帮助人类学习

  3. 什么是带标签的训练集?

    带标签的训练集表示在有样本的同时,还已知该样本的类别

  4. 最常见的两个监督任务是什么?

    分类和回归

  5. 指出四个常见的非监督任务?

    扫描二维码关注公众号,回复: 3194913 查看本文章

    聚类、可视化、降维和关联规则学习

  6. 要让一个机器人能在各种未知地形行走, 你会采用什么机器学习算法?

    如果我们想让机器人学会各种各样的走路方式,强化学习很可能表现得最好未知地形,因为这是强化学习处理的典型问题。可以将这个问题表述为一个有监督或半监督的学习问题,但这就不那么自然了。

  7. 要对你的顾客进行分组, 你会采用哪类算法?

    如果不知道如何定义组,那么可以使用聚类算法(无监督学习)将你的客户划分成类似客户的集群。然而,如果您知道您想拥有哪些组,那么您可以提供每个组的许多示例一个分类算法(监督学习),它将把你的所有客户分类这些团体。

  8. 垃圾邮件检测是监督学习问题, 还是非监督学习问题?

    垃圾邮件检测是一种典型的有监督学习问题:该算法向大量电子邮件发送与他们的标签(垃圾邮件或非垃圾邮件)。

  9. 什么是在线学习系统?

    在线学习系统可以增量学习,而不是批量学习系统。这使其能够快速适应不断变化的数据和自治系统,以及对大量数据进行培训。

  10. 什么是核外学习?

    核外学习算法可以处理大量无法装入计算机主程序的数据内存。一种非核心的学习算法将数据分解成小批量并在线使用学习从这些小批量中学习的技巧。

  11. 什么学习算法是用相似度做预测?

    基于实例的学习系统能够对训练数据进行记忆;然后,当给了一个新的实例,它使用相似度度量来查找最相似的已学习实例并使用它们作出预测。

  12. 模型参数和学习算法的超参数的区别是什么?

    一个模型有一个或多个模型参数,这些参数决定了在给定一个新实例(例如,线性模型的斜率)时它将预测什么。一个学习算法试图找到最优值这些参数使模型能够很好地推广到新的实例。超参数是A学习算法本身的参数,而不是模型的参数(例如,要应用的正则化量)

  13. 基于模型学习的算法搜寻的是什么? 最成功的策略是什么? 基于模型学习如何做预测?

    基于模型的学习算法搜索模型参数的最优值该模型将很好地推广到新的实例。

    我们通常通过最小化a来训练这样的系统衡量系统在预测训练数据方面有多差的成本函数,如果模型是正则化的,则会对模型复杂度造成惩罚。

    为了做出预测,我们将新实例的特征喂给模型的预测函数,使用学习到的参数。

  14. 机器学习的四个主要挑战是什么?

    数据不足、数据噪声太多或表现力不足、模型的过拟合和欠拟合

  15. 如果模型在训练集上表现好, 但推广到新实例表现差, 问题是什么? 给出三个可能的解决方案。

    出现了过拟合问题,可以增加更多的样本、简化模型、或清洗数据

  16. 什么是测试集, 为什么要使用它?

    测试集时为了在上线运行之前,估计模型在未知数据上的表现

  17. 验证集的目的是什么?

    验证集可以选择模型、选择最优超参数

  18. 如果用测试集调节超参数, 会发生什么?

    如果利用测试集条件超参数,则会让模型过度拟合测试集的分布,对未知数据有较差的泛化能力。

  19. 什么是交叉验证, 为什么它比验证集好?

    交叉验证是可以选择最优模型和超参数,交叉验证是循环使用k折中的一折来作为验证集,比单一的验证集有更好的泛化性能。

三、分类

1、二分类器

准确率P:预测为正例的样本中,有哪些是真正的正例

召回率R:预测为正例的样本中,占真正的正例的多少

F1_score:F1=2PR / P+R

from sklearn.metrics import precision_score,recall_score

precision_score(y_train,y_pred)
recall_score(y_train,y_pred)

准确率和召回率的平衡很重要,要根据不同场景来选择高召回率还是高准确率:

  • 高准确率:如果你训练一个分类器去检测视频是否适合儿童观看, 你会倾向选择那种即便拒绝了很多好视频、 但保证所保留的视频都是好( 高准确率) 的分类器, 而不是那种高召回率、 但让坏视频混入的分类器

  • 高召回率:加入你训练一个分类器去检测监控图像当中的窃贼, 有着 30% 准确率、 99% 召回率的分类器或许是合适的( 当然, 警卫会得到一些错误的报警, 但是几乎所有的窃贼都会被抓到) 。

  • 折中:分类的时候,会有一个阈值,如果分数大于阈值,则被分类为正例,否则分类为负例,提高阈值,分类为正例的概率会变小,准确率提高,但是召回率会降低;降低阈值,召回率会提高,准确率会降低。

可以将准确率和召回率当做阈值的一个函数,绘制出其曲线,可以选择适合任务的最佳阈值:

这里写图片描述

另一个选出其折衷的方法是直接绘制召回率-准确率曲线:

这里写图片描述

可以看到, 在召回率在 80% 左右的时候, 准确率急剧下降。 你可能会想选择在急剧下降之前
选择出一个准确率/召回率折衷点。 比如说, 在召回率 60% 左右的点。 当然, 这取决于你的项
目需求。

ROC曲线:

ROC 曲线是真正例率( true positive rate, 另一个名字叫做召回率) 对假正例率( false positive rate, FPR) 的曲线。

为了绘制ROC曲线,首先要计算各种不同阈值下的TPR和FPR,使用roc_curve()函数:

from sklearn.metrics import roc_curve
fpr,tpr,thresholds=roc_curve(y_train,y_scores)

使用matplotlib绘制FPR对TPR的曲线:

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')
    plt.ylabel('True Positive Rate')
plot_roc_curve(fpr, tpr)
plt.show()

这里写图片描述

这里同样存在折衷的问题: 召回率( TPR) 越高, 分类器就会产生越多的假正例( FPR) 。
图中的点线是一个完全随机的分类器生成的 ROC 曲线; 一个好的分类器的 ROC 曲线应该尽
可能远离这条线( 即向左上角方向靠拢) 。

一个比较分类器之间优劣的方法是: 测量ROC曲线下的面积( AUC) 。 一个完美的分类器的
ROC AUC 等于 1, 而一个纯随机分类器的 ROC AUC 等于 0.5。 Scikit-Learn 提供了一个函
数来计算 ROC AUC:

from sklearn.metrics import roc_auc_score
roc_auc_score(y_train,y_scores)

现在你知道如何训练一个二分类器, 选择合适的标准, 使用交叉验证去评估你的分类器, 选
择满足你需要的准确率/召回率折衷方案, 和比较不同模型的 ROC 曲线和 ROC AUC 数值。
现在让我们检测更多的数字, 而不仅仅是一个数字 5。

2、多分类器

一些算法( 比如随机森林分类器或者朴素贝叶斯分类器) 可以直接处理多类分类问题。 其他
一些算法( 比如 SVM 分类器或者线性分类器) 则是严格的二分类器。 然后, 有许多策略可以
让你用二分类器去执行多类分类。

例如要进行10类的分类:

  • 训练10个二分类器,每个对应于一个数字,当想对某张图像进行分类的时候,让每个分类器对该图像进行分类,选出决策分数最高的类别

  • 训练45个分类器,每个对应两类的区分,当想对一张图像进行分类的时候,必须将全部的45个二分类器全部跑完,看哪个类别的得分最多。

sklearn自动的执行的是一对多的分类器,

3、误差分析

检查混淆矩阵,需要使用cross_val_predict()做出预测,然后调用confusion_matrix()函数。

y_train_pred = cross_val_predict(sgd_clf, X_train_scaled, y_train, cv=3)
conf_mx = confusion_matrix(y_train, y_train_pred)
conf_mx

输出:

array([[5725, 3, 24, 9, 10, 49, 50, 10, 39, 4],
[ 2, 6493, 43, 25, 7, 40, 5, 10, 109, 8],
[ 51, 41, 5321, 104, 89, 26, 87, 60, 166, 13],
[ 47, 46, 141, 5342, 1, 231, 40, 50, 141, 92],
[ 19, 29, 41, 10, 5366, 9, 56, 37, 86, 189],
[ 73, 45, 36, 193, 64, 4582, 111, 30, 193, 94],
[ 29, 34, 44, 2, 42, 85, 5627, 10, 45, 0],
[ 25, 24, 74, 32, 54, 12, 6, 5787, 15, 236],
[ 52, 161, 73, 156, 10, 163, 61, 25, 5027, 123],
[ 43, 35, 26, 92, 178, 28, 2, 223, 82, 5240]])

使用matplotlibmatshow()函数,将混淆矩阵以图像的方式呈现,将会更加方便。

plt.matshow(conf_mx,cmap=plt.cm.gray)
plt.show()

这里写图片描述

这个混淆矩阵看起来相当好, 因为大多数的图片在主对角线上。 在主对角线上意味着被分类
正确。 数字 5 对应的格子看起来比其他数字要暗淡许多。 这可能是数据集当中数字 5 的图片
比较少, 又或者是分类器对于数字 5 的表现不如其他数字那么好。

四、训练模型

1、线性回归和逻辑回归

这里写图片描述

训练线性回归模型:训练一个模型是指设置模型的参数使得该模型在训练集上的表现较好,为此,要先找到一个衡量模型好坏的评定方法。常用评估回归的标准是RMSE,因此未来训练一个线性回归模型,需要通过梯度下降法或求解正规方程的方法来找到一个参数 θ ,使得预测和真实的均方误差最小。

这里写图片描述

正态方程求解:

这里写图片描述

生成一些近似线性的数据,来测试一下方程:

import numpy as np
x=2*np.random.ran(100,1)
y=4+3*x+np.random.randn(100,1)

这里写图片描述

现在让我们使用正态方程来计算 , 我们将使用 Numpy 的线性代数模块( np.linalg ) 中
的 inv() 函数来计算矩阵的逆, 以及 dot() 方法来计算矩阵的乘法

X_b = np.c_[np.ones((100, 1)), X]
theta_best = np.linalg.inv(X_b.T.dot(X_B)).dot(X_b.T).dot(y)

我们生产数据的函数实际上是y=4+3x 。 让我们看一下最后的计算结果。

theta_best
array([[4.21509616],[2.77011339]])

现在可以用 θ 来进行预测:

>>> X_new = np.array([[0],[2]])
>>> X_new_b = np.c_[np.ones((2, 1)), X_new]
>>> y_predict = X_new_b.dot(theta.best)
>>> y_predict
array([[4.21509616],[9.75532293]])

绘制:

plt.plot(X_new,y_predict,"r-")
plt.plot(X,y,"b.")
plt.axis([0,2,0,15])
plt.show()

这里写图片描述

计算复杂度:

正态方程需要计算 X T X 1 ,计算复杂度很高,但是线性情况下预测也是很快的。

梯度下降求解:

梯度下降是一种非常通用的优化算法, 它能够很好地解决一系列问题。 梯度下降的整体思路
是通过的迭代来逐渐调整参数使得损失函数达到最小值。

数值归一化很重要,否则会使得收敛很慢,模型不稳定,可能收敛不到局部最优点。

批量梯度下降 随机梯度下降 小批量梯度下降SGD

(1) 批量梯度下降

eta=0.1
n_iterations=1000
m=100

theta=np.random.randn(2,1)
for iteration in range(n_iterations):
    gradients=2/m*X_b.T.dot(X_b.dot(theta)-y)
    theta=theta-eta*gradients

输出:

theta
array([[4.21509616],[2.77011339]])

看! 正态方程的表现非常好。 完美地求出了梯度下降的参数。 但是当你换一个学习率会发生
什么? 图 4-8 展示了使用了三个不同的学习率进行梯度下降的前 10 步运算( 虚线代表起始位
置)
这里写图片描述

在左面的那副图中, 学习率是最小的, 算法几乎不能求出最后的结果, 而且还会花费大量的
时间。 在中间的这幅图中, 学习率的表现看起来不错, 仅仅几次迭代后, 它就收敛到了最后
的结果。 在右面的那副图中, 学习率太大了, 算法是发散的, 跳过了所有的训练样本, 同时
每一步都离正确的结果越来越远。

为了找到一个好的学习率, 你可以使用网格搜索( 详见第二章) 。 当然, 你一般会限制迭代
的次数, 以便网格搜索可以消除模型需要很长时间才能收敛这一个问题。

(2) 随机梯度下降

批量梯度下降的最要问题是计算每一步的梯度时都需要使用整个训练集, 这导致在规模较大
的数据集上, 其会变得非常的慢。 与其完全相反的随机梯度下降, 在每一步的梯度计算上只
随机选取训练集中的一个样本。 很明显, 由于每一次的操作都使用了非常少的数据, 这样使
得算法变得非常快。 由于每一次迭代, 只需要在内存中有一个实例, 这使随机梯度算法可以
在大规模训练集上使用。

其呈现出更多的不规律性: 它到达最小
值不是平缓的下降, 损失函数会忽高忽低, 只是在大体上呈下降趋势。 随着时间的推移, 它
会非常的靠近最小值, 但是它不会停止在一个值上, 它会一直在这个值附近摆动( 如图 4-
9) 。 因此, 当算法停止的时候, 最后的参数还不错, 但不是最优值

这里写图片描述

当损失函数很不规则时( 如图 4-6) , 随机梯度下降算法能够跳过局部最小值。 因此, 随机梯
度下降在寻找全局最小值上比批量梯度下降表现要好。

随机性可以很好的跳过局部最优值,但是不能达到局部最小值,因此,可以通过降低学习率的方法,也叫模拟退火法,使学习率越来越小,从而使算法到达全局最小值。

随机梯度下降代码:

n_epochs=50
t0,t1=5,50

def learning_schedule(t):
    return t0/(t+t1)
theta=np.random.randn(2,1)

for epoch in range(n_epochs):
    for i in range(m):
        random_index=np.random.randint(m)
        xi=X_b[random_index:random_index+1]
        yi=y[random_index:random_index+1]
        gradients=2*xi.T.dot(xi,dot(theta)-yi)
        eta=learning_schedule(epoch*m+i)
        theta=theta-eta*gradients
theta
array([[4.21076011],[2.748560791]])

图 4-10 展示了前 10 次的训练过程( 注意每一步的不规则程度) :

这里写图片描述

由于每个实例的选择是随机的, 有的实例可能在每一代中都被选到, 这样其他的实例也可能
一直不被选到。 如果你想保证每一次迭代过程, 算法可以遍历所有实例, 一种方法是将训练
集打乱重排, 然后选择一个实例, 之后再继续打乱重排, 以此类推一直进行下去。 但是这样
收敛速度会非常的慢。

通过使用 Scikit-Learn 完成线性回归的随机梯度下降, 你需要使用 SGDRegressor 类, 这个类
默认优化的是均方差损失函数。 下面的代码迭代了 50 代, 其学习率 为0.1( eta0=0.1 ) ,
使用默认的 learning schedule ( 与前面的不一样) , 同时也没有添加任何正则项
( penalty = None ) :

from sklearn.linear_model import SGDRegressor
    sgd_reg + SGDRregressor(n_iter=50, penalty=None, eta0=0.1)
    sgd_reg.fit(X,y.ravel())

(3) 小批量梯度下降

在迭代的每一步, 批量梯度使用整个训练集, 随机梯度时候用仅仅一个实例, 在小批量梯度下降中, 它则使用一个随机的小型实例集。 它比随机梯度的主要优点在于你可以通过矩阵运算的硬件优化得到一个较好的训练表现, 尤其当你使用 GPU 进行运算的时候。

小批量梯度下降在参数空间上的表现比随机梯度下降要好的多, 尤其在有大量的小型实例集
时。 作为结果, 小批量梯度下降会比随机梯度更靠近最小值。 但是, 另一方面, 它有可能陷
在局部最小值中( 在遇到局部最小值问题的情况下, 和我们之前看到的线性回归不一样) 。

图4-11显示了训练期间三种梯度下降算法在参数空间中所采用的路径。 他们都接近最小值,
但批量梯度的路径最后停在了最小值, 而随机梯度和小批量梯度最后都在最小值附近摆动。
但是, 不要忘记, 批次梯度需要花费大量时间来完成每一步, 但是, 如果你使用了一个较好
的 learning schedule , 随机梯度和小批量梯度也可以得到最小值。

这里写图片描述

2、逻辑回归

二分类模型,当估计概率大于50%的时候,模型预测该示例为正类,反之为负类。

逻辑回归是将线性回归的得分函数通过sigmoid函数映射为0~1之间的概率值,使用交叉熵损失函数作为损失函数,度量原始分布和预测分布的差别。

这里写图片描述

该损失函数是合理的,因为当一个样本为正例的时候,当p接近0的时候,-log(p)很大,也就是将正例判断为负例的时候,损失函数会很大,当p接近于1的时候,-log(p)接近于0,损失函数会很小。

整个训练集上的损失函数是所以实例的平均值,可以用一个表达式来统一表示,称为对数损失函数:

这里写图片描述

但是这个损失函数对于求解最小化损失函数的 是没有公式解的( 没有等价的正态方程) 。
但好消息是, 这个损失函数是凸的, 所以梯度下降( 或任何其他优化算法) 一定能够找到全
局最小值( 如果学习速率不是太大, 并且你等待足够长的时间) 。

这里写图片描述

3、softmax回归

逻辑回归是softmax回归的二分类时的特殊情况,可以将映射函数从sigmoid变为softmax就可以实现多分类,

这里写图片描述

和 Logistic 回归分类器一样, Softmax 回归分类器将估计概率最高( 它只是得分最高的类) 的
那类作为预测结果, 如公式 4-21 所示。

这里写图片描述

我们的目标是建立一个模型在目标类别上有着较高的概率,可以用交叉熵来定义当前的损失函数,当模型对目标类得出了一个较低的概率,会惩罚该模型,交叉熵通常用于衡量待测类别和目标类别的匹配程度。

这里写图片描述
这里写图片描述

练习题4
  1. 如果你有一个数百万特征的训练集,你应该选择哪种线性回归训练算法?

    可以使用随机梯度下降法或小批量梯度下降法,数据集太大基本无法使用全量梯度下降法,所需内存太大。

  2. 假设你训练集中特征的数值尺度(scale) 有着非常大的差异,哪种算法会受到影响?有
    多大的影响?对于这些影响你可以做什么?

    如果训练集的特征尺度差距太大,损失函数的等高线会呈椭圆状,利用梯度下降来求最优解的过程中会很难收敛,梯度方向变化很剧烈,收敛速度很慢,并且可能不会收敛到最优点。

  3. 训练 Logistic 回归模型时,梯度下降是否会陷入局部最低点?

    当训练一个逻辑回归模型的时候,梯度下降不会陷入局部最小值,因为损失函数是凸函数

  4. 在有足够的训练时间下,是否所有的梯度下降都会得到相同的模型参数?

    如果优化问题是凸的(如线性回归或逻辑回归),和假设学习率不是很高,那么所有的梯度下降算法都会接近全球最优,最终生产出相当相似的模型。不过,除非你渐渐降低学习率,随机GD和小批量GD永远不会真正收敛;相反,它们会在全局最优值附近来回跳跃。这意味着即使你让它们运行的时间很长,这些梯度下降算法产生的结果会略有不同模型。

  5. 假设你使用批量梯度下降法,画出每一代的验证误差。当你发现验证误差一直增大,接
    下来会发生什么?你怎么解决这个问题?

    如果验证误差一直增大的话,一种可能就是学习率过大,算法发散,可以降低学习率,还有一种可能就是过拟合了,应该早停训练。

  6. 当验证误差升高时,立即停止小批量梯度下降是否是一个好主意?

    由于梯度下降的随机性,不能保证在每轮迭代都会保证训练取得进展,如果马上停止训练的时候,可能会过早停止而无法达到最佳状态,更好的选择是定期保存模型,如果经过很长一段时间仍然没有改进的话,可以恢复到保存的最好模型。

  7. 哪个梯度下降算法(在我们讨论的那些算法中) 可以最快到达解的附近?哪个的确实会收敛?怎么使其他算法也收敛?

    随机梯度下降法的训练和迭代速度最快,因为它只考虑一次训练一个实例,因此它通常是第一个到达全局最优的附加的,然而只有批量梯度下降在给定足够的时间的时候是收敛的,也就是随机梯度下降和小批量梯度下降是都是收敛到最优解的附近,除非学习率下降到非常小。

  8. 假设你使用多项式回归,画出学习曲线,在图上发现学习误差和验证误差之间有着很大的间隙。这表示发生了什么?有哪三种方法可以解决这个问题?

    表明模型出现了过拟合的情况,在训练集上表现好,验证集上表现不好

    增加训练集、正则化、dropout

  9. 假设你使用岭回归,并发现训练误差和验证误差都很高,并且几乎相等。你的模型表现是高偏差还是高方差?这时你应该增大正则化参数 ,还是降低它?

    高偏差,可以降低正则化参数

  10. 你为什么要这样做:
    使用岭回归代替线性回归?

    • 模型有正则化的时候会比没有正则化的时候又更好的泛化性能,岭回归就是对模型的参数做了正则化,约束其幅值变化不能太大,否则会容易出现过拟合。

    Lasso 回归代替岭回归?

    • Lasso回归是L1正则化,也就是对模型参数的幅值正则化,该正则化也叫“稀疏选择算子”,可以对重要的特征进行选择,增加模型的可解释性,使得更多不重要的特征的权值置为0,只保留重要的特征,且越重要权重越高。

    弹性网络代替 Lasso 回归?

  11. 假设你想判断一副图片是室内还是室外,白天还是晚上。你应该选择二个逻辑回归分类
    器,还是一个 Softmax 分类器?

    可以选择两个逻辑回归来实现

  12. 在 Softmax 回归上应用批量梯度下降的早期停止法(不使用 Scikit-Learn) 。

五、SVM

支持向量机( SVM) 是个非常强大并且有多种功能的机器学习模型, 能够做线性或者非线性
的分类, 回归, 甚至异常值检测。 机器学习领域中最为流行的模型之一, 是任何学习机器学
习的人必备的工具。 SVM 特别适合应用于复杂但中小规模数据集的分类问题

在 Scikit-Learn 库的 SVM 类, 你可以用 C 超参数( 惩罚系数) 来控制这种平衡。

import numpy as np
from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC

iris = datasets.load_iris()
X = iris["data"][:, (2, 3)] # petal length, petal width
y = (iris["target"] == 2).astype(np.float64) # Iris-Virginica
svm_clf = Pipeline((
        ("scaler", StandardScaler()),
        ("linear_svc", LinearSVC(C=1, loss="hinge")),
    ))
svm_clf.fit(X_scaled, y)

Then, as usual, you can use the model to make predictions:
svm_clf.predict([[5.5, 1.7]])
array([ 1.])

logistics回归分类器输出的是概率,SVM分类器不会输出每个类别的概率。

作为一种选择, 你可以在 SVC 类, 使用 SVC(kernel=”linear”, C=1) , 但是它比较慢, 尤其在
较大的训练集上, 所以一般不被推荐。 另一个选择是使用 SGDClassifier 类,
即 SGDClassifier(loss=”hinge”, alpha=1/(m*C)) 。 它应用了随机梯度下降( SGD 见第四章)
来训练一个线性 SVM 分类器。 尽管它不会和 LinearSVC 一样快速收敛, 但是对于处理那些不
适合放在内存的大数据集是非常有用的, 或者处理在线分类任务同样有用。

利用SVM实现回归:你可以使用 Scikit-Learn 的 LinearSVR 类去实现线性 SVM 回归

练习题5
  1. 支持向量机背后的基本思想是什么

    支持向量机的背后的思想就是寻找具有最大间隔的分类平面,来对正负样本进行分类。

  2. 什么是支持向量

    支持向量就是在不改变分类平面方向的情况下来移动分类平面,分类平面会和样本点有接触,越过支持向量就会出现错分的情况。

  3. 当使用 SVM 时,为什么标准化输入很重要?

    SVM是尝试寻找出具有最大分类间隔的平面,所以如果不对输入进行归一化的话,SVM会更倾向于忽略小的特征,以大数量级的样本为主导。

    SVM 对特征缩放比较敏感,可以看到图 5-2:左边的图中,垂直的比例要更大于水平的
    比例,所以最宽的“街道”接近水平。但对特征缩放后(例如使用Scikit-Learn的StandardScaler) ,判定边界看起来要好得多,如右图。

这里写图片描述

  1. 分类一个样本时,SVM 分类器能够输出一个置信值吗?概率呢?

    SVM分类器可以输出测试示例与决策边界之间的距离,可以用这个作为信心指数,然后该分数不能直接转换成分类估计概率。

    1. 在一个有数百万训练样本和数百特征的训练集上,你是否应该使用 SVM 原始形式或对偶
      形式来训练一个模型?

    该问题只适用于线性SVM,因为内核化只能使用对偶形式,SVM的原始问题的计算复杂度是和实例数量m成正比的,对偶形式的计算复杂度处于 m 2 m 3 之间,所以对于百万以上的数据集,可以使用原始形式,因为对偶形式计算很慢。

    1. 假设你用 RBF 核来训练一个 SVM 分类器,如果对训练集欠拟合:你应该增大或者减
      小 γ 吗?调整参数 C 呢?

    如果训练集欠拟合的话,说明对误差的惩罚太小,对模型的约束太小,可以增大C,欠拟合说明RBF核的标准差太大,可以减小标准差,即增大 γ

    1. 使用现有的 QP 解决方案,你应该怎么样设置 QP 参数(H , f , A ,和 b ) 去解决
      一个软间隔线性 SVM 分类器问题?

    2. 在一个线性可分的数据集训练一个 LinearSVC ,并在同一个数据集上训练一
      个 SVC 和 SGDClassifier ,看它们是否产生了大致相同效果的模型。

    3. 在 MNIST 数据集上训练一个 SVM 分类器。因为 SVM 分类器是二元的分类,你需要使
      用一对多(one-versus-all) 来对 10 个数字进行分类。你可能需要使用小的验证集来调
      整超参数,以加快进程。最后你能达到多少准确度?

    4. 在加利福尼亚住宅(California housing) 数据集上训练一个 SVM 回归模型

六、决策树

练习题6
  1. 在 100 万例训练集上训练(没有限制) 的决策树的近似深度是多少?

    包含m个树叶的平衡良好的二叉树的深度等于log2(m),四舍五入。一个二叉决策树(一个只做二叉决策的树,就像ScikitLearn中的所有树一样)会在训练结束时或多或少地保持平衡,每次训练都有一片叶子实例,如果训练没有限制。因此,如果训练集包含一百万情况下,决策树的深度log2(10^6)≈20以来(实际上更多树一般不会完全平衡)

  2. 节点的基尼指数比起它的父节点是更高还是更低?它是通常情况下更高/更低,还是永远
    更高/更低?

    节点的基尼指数通常低于其父节点,这是由CART数的训练损失函数所确定的,每个节点经过最优属性分割之后,子节点的基尼指数之和都会小于父节点的基尼指数,然而如果一个孩子节点的基尼指数比另外一个的基尼指数小,则可能比其父节点的基尼不纯度更大,但是其基尼不纯度的增加肯定小于另外孩子基尼不纯度的减少。

  3. 如果决策树过拟合了,减少最大深度是一个好的方法吗?

    是一个好方法,可以对模型进行约束,使其规范化

  4. 如果决策树对训练集欠拟合了,尝试缩放输入特征是否是一个好主意?

    决策树对属性的数值缩放并不敏感,数值缩放不会影响其最优分裂点的选择,

  5. 如果对包含 100 万个实例的数据集训练决策树模型需要一个小时,在包含 1000 万个实
    例的培训集上训练另一个决策树大概需要多少时间呢?

    决策树的计算复杂度为 O ( n × m l o g ( m ) ) 所以如果训练集增加了10倍,复杂度会增加以下倍数 K = ( n × 10 m × l o g ( 10 m ) ) / ( n × m × l o g ( m ) = 10 × l o g ( 10 m ) / l o g ( m ) ,如果m=10^6,K=11.7,大概需要11.7小时

  6. 如果你的训练集包含 100,000 个实例,设置 presort=True 会加快训练的速度吗?

只有当数据集小于几千时,才会加速训练实例。如果它包含100,000个实例,那么设置presort=True的训练将会慢得多。

七、集成学习

接下来的代码创建和训练了在 sklearn 中的投票分类器。 这个分类器由三个不同的分类器组成
( 训练集是第五章中的 moons 数据集) :

>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.ensemble import VotingClassifier
>>> from sklearn.linear_model import LogisticRegression
>>> from sklearn.svm import SVC
>>> log_clf = LogisticRegression()
>>> rnd_clf = RandomForestClassifier()
>>> svm_clf = SVC()
>>> voting_clf = VotingClassifier(estimators=[('lr', log_clf), ('rf', rnd_clf), >>> ('
svc', svm_clf)],voting='hard')
>>> voting_clf.fit(X_train, y_train)

让我们看一下在测试集上的准确率:

>>> from sklearn.metrics import accuracy_score
>>> for clf in (log_clf, rnd_clf, svm_clf, voting_clf):
>>> clf.fit(X_train, y_train)
>>> y_pred = clf.predict(X_test)
>>> print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
LogisticRegression 0.864
RandomForestClassifier 0.872
SVC 0.888
VotingClassifier 0.896

投票分类器比其他单独的分类器表现的都要好

sklearn中的bagging

接下来的代码训练了一个 500 个决策树分类器的集成, 每一个都是在数据集上有放回采样 100 个训练实例下进行训练

n_jobs 参数告诉 sklearn 用于训练和预测所需要 CPU核的数量。 ( -1 代表着 sklearn 会使用所有空闲核) :

>>>from sklearn.ensemble import BaggingClassifier
>>>from sklearn.tree import DecisionTreeClassifier
>>>bag_clf = BaggingClassifier(DecisionTreeClassifier(), n_estimators=500,max_samples=100, bootstrap=True, n_jobs=-1)
>>>bag_clf.fit(X_train, y_train)
>>>y_pred = bag_clf.predict(X_test)

图 7-5 对比了单一决策树的决策边界和 Bagging 集成 500 个树的决策边界, 两者都在 moons
数据集上训练。 正如你所看到的, 集成的分类比起单一决策树的分类产生情况更好: 集成有
一个可比较的偏差但是有一个较小的方差( 它在训练集上的错误数目大致相同, 但决策边界
较不规则) 。

这里写图片描述

out-of-bag评价:

对于 Bagging 来说, 一些实例可能被一些分类器重复采样, 但其他的有可能不会被采样。 BaggingClassifier 默认采样。 BaggingClassifier 默认是有放回的采样 m 个实例( bootstrap=True ) , 其中 m 是训练集的大小, 这意味着平均下来只有63%的训练实例被每个分类器采样, 剩下的37%个没有被采样的训练实例就叫做 Out-of-Bag 实例。 注意对于每一个的分类器它们的 37% 不是相同的。

因为在训练中分类器从来没有看到过 oob 实例, 所以它可以在这些实例上进行评估, 而不需要单独的验证集或交叉验证。 你可以拿出每一个分类器的 oob 来评估集成本身。

在 sklearn 中, 你可以在训练后需要创建一个 BaggingClassifier 来自动评估时设
置 oob_score=True 来自动评估。 接下来的代码展示了这个操作。 评估结果通过变
量 oob_score_ 来显示:

>>> bag_clf = BaggingClassifier(DecisionTreeClassifier(), n_estimators=500,bootstrap=T
rue, n_jobs=-1, oob_score=True)
>>> bag_clf.fit(X_train, y_train)
>>> bag_clf.oob_score_
0.93066666666666664

Adabooost:

>>>from sklearn.ensemble import AdaBoostClassifier
>>>ada_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), n_estimators=200,algorithm="SAMME.R", learning_rate=0.5)
>>>ada_clf.fit(X_train, y_train)

如果你的 Adaboost 集成过拟合了训练集, 你可以尝试减少基分类器的数量或者对基分类器使
用更强的正则化。

GBDT:

梯度提升也是通过向集成中逐步增加分类器运行的, 每一个分类器都修正之前的分类结果。 然而, 它并不像 Adaboost 那样每一次迭代都更改实例的权重, 这个方法是去使用新的分类器去拟合前面分类器预测的残差。

梯度提升回归树(GBRT):

# 首先用DecisionTreeRegressor来拟合训练集
from sklearn.tree import DecisionTreeRegressor
tree_reg1=DecisionTreeRgressor(max_depth=2)
tree_reg1.fit(X,y)

# 之后在第一个分类器的残差上训练第二个分类器
y2=y-tree_reg1.predict(X)
tree_reg2=DecisionTreeRegressor(max_depth=2)
tree_reg2.fit(X,y2)

# 随后在第二个分类器的残差上训练第三个分类器
y3 = y2 - tree_reg1.predict(X)
tree_reg3 = DecisionTreeRegressor(max_depth=2)
tree_reg3.fit(X, y3)

# 现在我们有了一个包含三个回归器的集成。 它可以通过集成所有树的预测来在一个新的实例
上进行预测。
y_pred=sum(tree.predict(X_new) for tree in (tree_reg1,tree_reg2,tree_reg3))

图7-9在左栏展示了这三个树的预测, 在右栏展示了集成的预测。 在第一行, 集成只有一个
树, 所以它与第一个树的预测相似。 在第二行, 一个新的树在第一个树的残差上进行训练。
在右边栏可以看出集成的预测等于前两个树预测的和。 相同的, 在第三行另一个树在第二个
数的残差上训练。 你可以看到集成的预测会变的更好。
这里写图片描述
sklearn中可以使用GradientBoostingRegressor来训练梯度回归树,与RandomForestClassifier 相似, 它也有超参数去控制决策树的生长( 例如 max_depth , min_samples_leaf 等等) , 也有超参数去控制集成训练, 例如基分类器的数量( n_estimators ) 。 接下来的代码创建了与之前相同的集成:

from sklearn.ensemble import GradientBoostingRegressor
gbrt = GradientBoostingRegressor(max_depth=2,n_estimators=3,learning_rate=1.0)
gbrt.fit(X,y)

超参数learning_rate确立了每个树的贡献,如果你把它设置为一个很小的树, 例如 0.1, 在
集成中就需要更多的树去拟合训练集, 但预测通常会更好。 这个正则化技术叫做 shrinkage

图 7-10 展示了两个在低学习率上训练的 GBRT 集成: 其中左面是一个没有足够树去拟合训练
集的树, 右面是有过多的树过拟合训练集的树

这里写图片描述

下面的代码用120个树训练了一个GBRT集成,然后在训练的每个阶段验证错误以找到树的最佳数量,最后使用GBRT树的最优数量训练另一个集成。

>>>import numpy as np
>>>from sklearn.model_selection import train_test_split
>>>from sklearn.metrics import mean_squared_error
>>>X_train, X_val, y_train, y_val = train_test_split(X, y)
>>>gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=120)
>>>gbrt.fit(X_train, y_train)
>>>errors = [mean_squared_error(y_val, y_pred)
for y_pred in gbrt.staged_predict(X_val)]
>>>bst_n_estimators = np.argmin(errors)
>>>gbrt_best = GradientBoostingRegressor(max_depth=2,n_estimators=bst_n_estimators)
>>>gbrt_best.fit(X_train, y_train)
练习题7
  1. 如果你在相同训练集上训练 5 个不同的模型,它们都有 95% 的准确率,那么你是否可以
    通过组合这个模型来得到更好的结果?如果可以那怎么做呢?如果不可以请给出理由。

    可以使用集成学习并结合投票规则来获得更好的准确率,集成学习的基学习器有很大的不同的时候会有较好的投票结果,利用不同的数据集学到的基学习器的组合同样可以获得较好的效果。

  2. 软投票和硬投票分类器之间有什么区别?

    硬投票分类器只计算集合中每个分类器的投票,并选择得到最多选票的类,软投票分类器计算每个类的平均估计类概率,并选择概率最高的类,也就是给置信度高的类更高的权重,但是前提是可以得到每个类的概率。

  3. 是否有可能通过分配多个服务器来加速 bagging 集成系统的训练?pasting 集成,boosting 集成,随机森林,或 stacking 集成怎么样?

    boosting集成是串行生成的基分类器,不能分布式进行。
    bagging、pasting、stacking都可以并行进行

  4. out-of-bag 评价的好处是什么?

    在包外评估中,包外集成中的每个预测器都使用它没有经过训练的实例进行评估(它们被保留了下来)。这样就可以对集成进行相当公正的评估,而不需要额外的验证集。这样,您就有了更多可用的实例来进行培训,您的集成可以稍微好一些。

  5. 是什么使 Extra-Tree 比规则随机森林更随机呢?这个额外的随机有什么帮助呢?那这个
    Extra-Tree 比规则随机森林谁更快呢?

    当您在随机森林中种植一棵树时,只考虑在每个节点上分割特征的一个随机子集。对于额外树来说也是如此,但是它们更进一步:不像常规的决策树那样搜索可能的最佳阈值,而是对每个特性使用随机阈值。这种额外的随机性就像一种正则化的形式:如果一个随机森林超过了训练数据,额外的树可能会表现得更好。此外,由于额外的树不会搜索最好的阈值,它们比随机森林训练的速度要快得多。然而,它们在进行预测时既不比随机森林快也不慢。

  6. 如果你的 Adaboost 模型欠拟合,那么你需要怎么调整超参数?

    增加样本量、减小正则化程度,提高模型速度

  7. 如果你的梯度提升过拟合,那么你应该调高还是调低学习率呢?

    降低学习率,或使用早停的方法来寻找正确数量的基学习器。

八、降维

PCA:常用的线性降维方法它的目标是通过某种线性投影,将高维的数据映射到低维的空间中表示,即把原先的n个特征用数目更少的m个特征取代,新特征是旧特征的线性组合。并期望在所投影的维度上数据的方差最大,尽量使新的m个特征互不相关。从旧特征到新特征的映射捕获数据中的固有变异性。以此使用较少的数据维度,同时保留住较多的原数据点的特性。

很多机器学习的问题都会涉及到有着几千万甚至数百万维的特征的训练实例,这会使得训练过程非常缓慢,同时很难找到一个很好的解,也称为维数灾难。

降维可以加快训练速度,也可以提高数据可视化的程度。

PCA:将数据投影到具有最大方差的坐标轴上,可以损失更少的信息,也可以使得原始数据集投影到该轴上的均方距离最小。

  • 首先寻找具有最大方差的轴:最大化的保留原始数据的信息

  • 之后寻找和第一条轴正交的轴作为第二条轴,保证可以获得最大的残差

备注:主成分的方向不稳定: 如果您稍微打乱一下训练集并再次运行 PCA, 则某些新PC 可能会指向与原始 PC 方向相反。 但是, 它们通常仍位于同一轴线上。 在某些情况下, 一对 PC 甚至可能会旋转或交换, 但它们定义的平面通常保持不变。

如何找到主成分:利用奇异值分解SVD对矩阵进行分解,

X_centered=X-X.mean(axis=0)
U,s,V=np.linalg.svd(X_centered)
c1=V.T[:,0]
c2=V.T[:,1]

PCA 假定数据集以原点为中心。 正如我们将看到的, Scikit-Learn 的 PCA 类负责
为您的数据集中心化处理。 但是, 如果您自己实现 PCA( 如前面的示例所示) , 或者如
果您使用其他库, 不要忘记首先要先对数据做中心化处理。

投影:一旦确定了所有的主成分,可以选择将数据集投影到由前d个主成分构成的超平面上,从而将数据集降至d维,为了将训练集投影到超平面上, 可以简单地通过计算训练集矩阵 X 和 Wd 的点积, Wd 定义为包含前 d 个主成分的矩阵( 即由 V^T 的前 d 列组成的矩阵)

方差解释率:另一个非常有用的信息是每个主成分的方差解释率, 可以通过explained_variance_ratio_变量获得,表示位于每个主成分轴上的数据集方差的比例。

print(pca.explained_variance_ratio_)
array([0.84248607, 0.14631839])

这表明, 84.2% 的数据集方差位于第一轴, 14.6% 的方差位于第二轴。 第三轴的这一比例不
到1.2%, 因此可以认为它可能没有包含什么信息。

通常我们倾向于选择加起来到方差解释率能够达到足够占比( 例如 95%) 的维度的数量, 而
不是任意选择要降低到的维度数量。 当然, 除非您正在为数据可视化而降低维度 – 在这种情
况下, 您通常希望将维度降低到 2 或 3。

其他降维方法:

还有很多其他的降维方法, Scikit-Learn 支持其中的好几种。 这里是其中最流行的:

  • 多维缩放MDS:在尝试保持实例之间距离的同时降低了维度( 参见图 8-13)

  • t-分布随机邻域嵌入( t-Distributed Stochastic Neighbor Embedding, t-SNE) 可以用于降低维​度, 同时试图保持相似的实例临近并将不相似的实例分开。 它主要用于可视化,尤其是用于可视化高维空间中的实例( 例如, 可以将MNIST图像降维到 2D 可视化) 。

  • 线性判别分析( Linear Discriminant Analysis, LDA) 实际上是一种分类算法, 但在训练过程中, 它会学习类之间最有区别的轴, 然后使用这些轴来定义用于投影数据的超平面。 LDA 的好处是投影会尽可能地保持各个类之间距离, 所以在运行另一种分类算法( 如 SVM 分类器) 之前, LDA 是很好的降维技术

练习题8
  1. 减少数据集维度的主要动机是什么?主要缺点是什么?

    主要动机:加速训练,去除噪声和冗余特征,使得算法性能更好;可以可视化来寻找更好的特征;可以节省空间。

    主要缺点:会丢失部分信息,可能降低后续算法的性能;是计算密集型的;增加了机器学习管道的复杂性;降低可解释性

  2. 什么是维度爆炸?

    维度爆炸是指高维空间中出现了许多低维空间不存在的问题,在机器学习中,一个常见的表现是,随机采样的高维向量通常非常稀疏,增加了过度拟合的风险,使得在没有大量训练数据的情况下很难识别数据中的模式。

  3. 一旦对某数据集降维,我们可能恢复它吗?如果可以,怎样做才能恢复?如果不可以,
    为什么?

    一旦数据集通过降维降到了一个较小的维度,就几乎不会是想完全的复现,因为在维度减小的过程中,已经有信息丢失了,虽然PCA有逆过程,但可以重构一个和原始数据集比较相似的数据集,但是t-SNE没有。

  4. PCA 可以用于降低一个高度非线性对数据集吗?

    PCA可以显著降低大多数数据集的维数,即使他们是高度非线性的,因为它至少可以消除无用的维度,然而如果每个维度都很有用,那么利用PCA之后丢失很多的信息。

  5. 假设你对一个 1000 维的数据集应用 PCA,同时设置方差解释率为 95%,你的最终数据
    集将会有多少维?

    这是一个棘手的问题:它取决于数据集。让我们来看两个极端的例子。首先,假设数据集由几乎完全对齐的点组成。在这种情况下,PCA可以将数据集减少到一个维度,同时仍然保留95%的方差。现在假设数据集由完全随机的点组成,散布在1000个点周围维度。在这种情况下,所有1000维都需要保持95%的方差。所以答案是,它取决于数据集,它可以是1到1000之间的任何数字。把被解释的方差作图成维数的函数是得到a的一种方法数据集固有维数的粗略概念

  6. 在什么情况下你会使用普通的 PCA,增量 PCA,随机 PCA 和核 PCA?

    常规PCA是默认值,但它只在数据集适合内存的情况下工作。增量PCA对于不适合内存的大型数据集有用,但它比常规PCA要慢,所以如果数据集适合内存你应该喜欢常规的PCA。

    增量PCA也适用于在线任务,当您需要动态应用PCA时,每当一个新实例到达时。随机当您想要大大减少维度并且数据集适合时,PCA是有用的记忆;在这种情况下,它比普通PCA快得多。

    最后,核PCA是对非线性数据集有用。

  7. 你该如何评价你的降维算法在你数据集上的表现?

    直观地说,如果一个降维算法在不丢失太多信息的情况下从数据集中消除了大量的维数,那么它的性能就会很好。一种测量方法是应用反向变换并测量重构误差。然而,并不是所有的降维算法都提供了反向转换。或者,如果您使用降维作为另一种机器学习算法(例如,随机森林分类器)之前的预处理步骤,那么您可以简单地测量第二种算法的性能;如果降维不会丢失太多信息,那么算法的性能应该与使用原始数据集时一样好。

  8. 将两个不同的降维算法串联使用有意义吗?

    将两种不同的降维算法串联起来是绝对有意义的。一个常见的例子是使用PCA快速摆脱大量无用的维数,然后应用另一种慢得多的降维算法,如LLE。这种分两步的方法可能会产生与仅使用LLE相同的性能,但只是一小部分时间。

猜你喜欢

转载自blog.csdn.net/jiaoyangwm/article/details/82387883